Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Regexp查找两个字符串的最长公共前缀_Python_Ruby_Regex_Perl_Replace - Fatal编程技术网

Python Regexp查找两个字符串的最长公共前缀

Python Regexp查找两个字符串的最长公共前缀,python,ruby,regex,perl,replace,Python,Ruby,Regex,Perl,Replace,是否有一个regexp可以找到两个字符串的最长公共前缀?如果一个regexp无法解决这个问题,那么使用regexp(perl、ruby、python,任何东西)的最优雅的代码或一行代码是什么呢 PS:我可以通过编程很容易地做到这一点,我是出于好奇,因为在我看来,这可以通过regexp解决 PPS:使用正则表达式的O(n)解决方案的额外奖金。来吧,它应该存在 如果两个字符串都不包含某个字符,例如,\0,则可以编写 "$first\0$second" =~ m/^(.*).*\0\1/s; 最长的

是否有一个regexp可以找到两个字符串的最长公共前缀?如果一个regexp无法解决这个问题,那么使用regexp(perl、ruby、python,任何东西)的最优雅的代码或一行代码是什么呢

PS:我可以通过编程很容易地做到这一点,我是出于好奇,因为在我看来,这可以通过regexp解决


PPS:使用正则表达式的O(n)解决方案的额外奖金。来吧,它应该存在

如果两个字符串都不包含某个字符,例如,
\0
,则可以编写

"$first\0$second" =~ m/^(.*).*\0\1/s;
最长的公共前缀将保存为
$1


编辑后添加:这显然效率很低。我认为,如果效率是一个问题,那么这根本不是我们应该使用的方法;但我们至少可以通过将
*
更改为
[^\0]*
来改进它,以防止无用的贪婪再次被回溯,并将第二个
[^\0]*
包装在
(?>…)
中以防止无济于事的回溯。这:

"$first\0$second" =~ m/^([^\0]*)(?>[^\0]*)\0\1/s;

这将产生相同的结果,但效率更高。(但仍然不如基于非正则表达式的直接方法有效。如果字符串都有长度n,我预计其最坏情况至少需要O(n2)时间,而基于非正则表达式的直接方法在其最坏情况下需要O(n)时间。)

这里有一个Python单行程序:

>>> a = 'stackoverflow'
>>> b = 'stackofpancakes'
>>> a[:[x[0]==x[1] for x in zip(a,b)].index(0)]
0: 'stacko'
>>> a = 'nothing in'
>>> b = 'common'
>>> a[:[x[0]==x[1] for x in zip(a,b)].index(0)]
1: ''
>>> 

每个迭代解决方案中的非regexp、非重复字符串:

def common_prefix(a, b):
   #sort strings so that we loop on the shorter one
   a, b = sorted((a,b), key=len)
   for index, letter in a:
      if letter != b[index]:
          return a[:index - 1]
   return a
"$first \0$second" =~ m/^(.*?)(.).*\0\1(?!\2)/s;
$x=length($first); $_="$first\0$second"; s/((.)(?!.{$x}\2)).*//s;

您将遇到的问题是,正则表达式一次与一个字符串匹配,因此不用于比较两个字符串

如果有一个字符,您可以确定它不在任何一个字符串中,您可以使用它将它们分隔在一个字符串中,然后使用对组的反向引用进行搜索

在下面的例子中,我使用空格作为分隔符

>>> import re
>>> pattern = re.compile("(?P<prefix>\S*)\S*\s+(?P=prefix)")
>>> pattern.match("stack stable").group('prefix')
'sta'
>>> pattern.match("123456 12345").group('prefix')
'12345'
>>重新导入
>>>模式=重新编译((?P\S*)\S*\S+(?P=前缀)”)
>>>pattern.match(“堆栈稳定”).group(“前缀”)
“sta”
>>>pattern.match(“123456 12345”).group(“前缀”)
'12345'

我认为这是最低效的。无错误检查等

#!/usr/bin/perl
use strict;
use warnings;

my($s1,$s2)=(@ARGV);
#find the shortest string put it into s1, if you will.

my $n=0;
my $reg;

foreach my $c (split(//,$s1)) { $reg .="($c"; $n++;}

$reg .= ")?" x $n;

$s2 =~ /$reg/; 

print $&,"\n";

我支持ruakh对regexp的回答(在评论中有我建议的优化)。编写起来很简单,但如果第一个字符串很长,那么运行起来就不简单且效率不高

以下是一个高效、非regexp、可读的单行答案:

$ perl -E '($n,$l)=(0,length $ARGV[0]); while ($n < $l) { $s = substr($ARGV[0], $n, 1); last if $s ne substr($ARGV[1], $n, 1); $n++ } say substr($ARGV[0], 0, $n)' abce abcdef
abc
$perl-E'($n,$l)=(0,长度$ARGV[0]);而($n<$l){$s=substr($ARGV[0],$n,1);last if$s ne substr($ARGV[1],$n,1);$n++}表示substr($ARGV[0],0,$n)'abce abcdef
abc
简单高效

def common_prefix(a,b):
  i = 0
  for i, (x, y) in enumerate(zip(a,b)):
    if x!=y: break
  return a[:i]

受ruakh答案的启发,以下是O(n)regexp解决方案:

def common_prefix(a, b):
   #sort strings so that we loop on the shorter one
   a, b = sorted((a,b), key=len)
   for index, letter in a:
      if letter != b[index]:
          return a[:index - 1]
   return a
"$first \0$second" =~ m/^(.*?)(.).*\0\1(?!\2)/s;
$x=length($first); $_="$first\0$second"; s/((.)(?!.{$x}\2)).*//s;
注: 1.两个字符串都不包含\0 2.最长的通用前缀将另存为$1 3.空间很重要

编辑:它不像rukach metions那样正确,但是这个想法是正确的,但是我们应该推动regexp机器,不要重复检查开头字母。基本思想也可以在这个perl oneliner中重写

perl -e ' $_="$first\0$second\n"; while(s/^(.)(.*?)\0\1/\2\0/gs) {print $1;}; '

我想知道是否可以将它合并到regexp解决方案中。

这里有一种使用regexp的相当有效的方法。代码是用Perl编写的,但原则应适用于其他语言:

my $xor = "$first" ^ "$second";    # quotes force string xor even for numbers
$xor =~ /^\0*/;                    # match leading null characters
my $common_prefix_length = $+[0];  # get length of match
(值得注意的一个微妙之处是Perl的字符串异或运算符(
^
)实际上,将较短字符串填充为空以匹配较长字符串的长度。因此,如果字符串可能包含空字符,并且较短字符串恰好是较长字符串的前缀,则使用此代码计算的公共前缀长度可能会超过较短字符串的长度。)

O(n)解决方案的另一次尝试:

def common_prefix(a, b):
   #sort strings so that we loop on the shorter one
   a, b = sorted((a,b), key=len)
   for index, letter in a:
      if letter != b[index]:
          return a[:index - 1]
   return a
"$first \0$second" =~ m/^(.*?)(.).*\0\1(?!\2)/s;
$x=length($first); $_="$first\0$second"; s/((.)(?!.{$x}\2)).*//s;
这取决于{n}被认为是O(1)还是O(n),我不知道这个实现的效率有多高


注:1\0不应位于用作分隔符2的两个字符串中。结果是在$

中使用Foma或Xfst中的扩展正则表达式

def range(x) x.l;
def longest(L) L - range(range(L ∘ [[Σ:ε]+ [Σ:a]*]) ∘ [a:Σ]*); 
def prefix(W) range(W ∘ [Σ* Σ*:ε]);
def lcp(A,B) longest(prefix(A) ∩ prefix(B));
这里最难的部分是定义“最长”。一般来说 优化,您可以构造非最佳字符串集(恶化)和 然后移除这些(过滤)

这实际上是一种纯粹的方法,它避免了非常规操作 这是一个很好的例子

这是一个O(N)解决方案,它在三元组上使用类似于Foma的伪代码正则表达式(对于lcp,您有两个输入和一个输出)。为了简单起见,我假设一个二进制字母{a,b}:

def match {a:a:a, b:b:b};
def mismatch {a:b:ε, b:a:ε};
def lcp match* ∪ (match* mismatch (Σ:Σ:ε)*)
现在,您只需要一种实现多磁带传感器的语言。

在某些远程情况下可能很有用,因此,下面介绍:

仅限正则表达式的解决方案分3步执行(无法一次性创建正则表达式):

字符串A:
abcdef

字符串B:
abcxef

  • 第一步:从
    字符串A创建正则表达式(第1部分):
    匹配:
    /()/g

    替换:
    \1(

    结果:
    a(b)c(d)e(f
    演示说明:

  • 第二遍:从第一遍结果创建正则表达式 匹配:
    /^(.\()(?=(.*)$)\G.\(/G

    替换:
    \1\2)?+

    结果:
    a(b(c(d)(e(f()?+)?+)?+)?+)?+)?+)?+

    演示说明:

  • 第三遍:根据在第二遍中创建的正则表达式测试字符串B 匹配:
    /a(b(c(d)(e(f()?+)?+)?+)?+)?+)?+)?+/

    结果:
    abc
    ()

下面是PHP中美化的一行程序:

preg_match('/^'.preg_replace('/^(.\()(?=(.*)$)|\G.\(/','\1\2)?+',preg_replace('/(.)/','\1(',$a)).'/',$b,$longest);

代码在:

以下是我为leetcode问题实施的解决方案:

def max_len(strs):
    """
    :type strs: List[str]
    :rtype: int
    """
    min_s = len(strs[0]);
    for s in strs:
        if (len(s) < min_s):
            min_s = len(s);
    return min_s;


class Solution2:
    def longestCommonPrefix(self, strs):
    """
    :type strs: List[str]
    :rtype: str
    """
    acc = -1;
    test_len = max_len(strs);
    for i in range(test_len):
        t = strs[0][i];
        acc2 = 0;
        for j in range(len(strs)):
            if (strs[j][i] == t):
                acc2 += 1;
        if (acc2 == len(strs)):
            acc += 1;

    if (acc == -1):
        return ""
    else:
        return strs[0][:acc + 1]
def最大长度(strs):
"""
:类型strs:List[str]
:rtype:int
"""
min_s=len(strs[0]);
对于STR中的s:
如果(长度<最小值):
最小值=最小值;
返回最小值;
类别解决方案2:
def最长通用前缀(self,strs):
"""
:类型strs:List[str]
:rtype:str
"""
acc=-1;
测试长度=最大长度(strs);
对于范围内的i(测试范围):
t=strs[0][i];
acc2=0;