Python Regexp查找两个字符串的最长公共前缀
是否有一个regexp可以找到两个字符串的最长公共前缀?如果一个regexp无法解决这个问题,那么使用regexp(perl、ruby、python,任何东西)的最优雅的代码或一行代码是什么呢 PS:我可以通过编程很容易地做到这一点,我是出于好奇,因为在我看来,这可以通过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; 最长的
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
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;