如何编写一个完全匹配相同字符(或理想情况下,同一组)的N次重复的表达式?基本上,(.)\1{N-1}
做了什么,但有一个重要的限制:如果主题重复更多而不是N次,则表达式应该失败。例如,给定N=4
和字符串xxaaaayyybbbbbzzccccxx
,表达式应与aaaa
和cccc
匹配,而不是bbbb
。
我不专注于任何特定的方言,随意使用任何语言。请不要发布仅适用于此特定示例的代码,我正在寻找一般解决方案。
答案 0 :(得分:11)
使用否定前瞻和否定后视。
这将是正则表达式:(.)(?<!\1.)\1{N-1}(?!\1)
,除了Python的re模块被破坏(参见this link)。
英语翻译:“匹配任何一个角色。确保在匹配该角色后,前面的角色也不是那个角色。再匹配N-1个角色的重复次数。确保重复之后的角色是不是那个角色。“
不幸的是,re模块(和大多数正则表达式引擎)都被破坏了,因为你不能在lookbehind断言中使用反向引用。 Lookbehind断言需要是恒定长度,并且编译器不够聪明,无法推断它是在使用反向引用时(即使在这种情况下,backref具有恒定长度)。我们必须通过这个来处理正则表达式编译器,如下所示:
实际答案必须更加混乱:r"(.)(?<!(?=\1)..)\1{N-1}(?!\1)"
这可以通过使用(?=\1)..
代替\1.
来解决re模块中的错误(这些错误在大多数情况下是等效的。)这使得正则表达式引擎可以准确地知道后瞻断言的宽度,所以它适用于PCRE和重复等等。
当然,现实世界的解决方案就像[x.group() for x in re.finditer(r"(.)\1*", "xxaaaayyybbbbbzzccccxx") if len(x.group()) == 4]
答案 1 :(得分:6)
我怀疑你想要使用否定前瞻:(.)\1{N-1}(?!\1)
。
但是那说......我怀疑最简单的跨语言解决方案只是自己编写而不使用正则表达式。
更新:
^(.)\\1{3}(?!\\1)|(.)(?<!(?=\\2)..)\\2{3}(?!\\2)
更适用于我,包括从字符串开头开始的匹配。
答案 2 :(得分:2)
很容易对正则表达式施加太多负担并尝试让他们做所有,只需几乎一切都会做到!
使用正则表达式查找由单个字符组成的所有子字符串,然后分别检查它们的长度,如下所示:
use strict;
use warnings;
my $str = 'xxaaaayyybbbbbzzccccxx';
while ( $str =~ /((.)\2*)/g ) {
next unless length $1 == 4;
my $substr = $1;
print "$substr\n";
}
<强>输出强>
aaaa
cccc
答案 3 :(得分:2)
Perl的正则表达式引擎不支持可变长度的lookbehind,所以我们必须慎重考虑它。
sub runs_of_length {
my($n,$str) = @_;
my $n_minus_1 = $n - 1;
my $_run_pattern = qr/
(?:
# In the middle of the string, we have to force the
# run being matched to start on a new character.
# Otherwise, the regex engine will give a false positive
# by starting in the middle of a run.
(.) ((?!\1).) (\2{$n_minus_1}) (?!\2) |
#$1 $2 $3
# Don't forget about a potential run that starts at
# the front of the target string.
^(.) (\4{$n_minus_1}) (?!\4)
# $4 $5
)
/x;
my @runs;
while ($str =~ /$_run_pattern/g) {
push @runs, defined $4 ? "$4$5" : "$2$3";
}
@runs;
}
一些测试用例:
my @tests = (
"xxaaaayyybbbbbzzccccxx",
"aaaayyybbbbbzzccccxx",
"xxaaaa",
"aaaa",
"",
);
$" = "][";
for (@tests) {
my @runs = runs_of_length 4, $_;
print qq<"$_":\n>,
" - [@runs]\n";
}
输出:
"xxaaaayyybbbbbzzccccxx": - [aaaa][cccc] "aaaayyybbbbbzzccccxx": - [aaaa][cccc] "xxaaaa": - [aaaa] "aaaa": - [aaaa] "": - []
这是一个有趣的谜题,但是如果这样的结构出现在生产代码中,你的正则表达式的同事可能会感到不快。
答案 4 :(得分:1)
>>> import itertools
>>> zz = 'xxaaaayyybbbbbzzccccxxaa'
>>> z = [''.join(grp) for key, grp in itertools.groupby(zz)]
>>> z
['xx', 'aaaa', 'yyy', 'bbbbb', 'zz', 'cccc', 'xx', 'aa']
从那里你可以遍历列表并检查N==4
非常容易的场合,如下所示:
>>> [item for item in z if len(item)==4]
['cccc', 'aaaa']
答案 5 :(得分:1)
在python中这个怎么样?
def match(string, n):
parts = []
current = None
for c in string:
if not current:
current = c
else:
if c == current[-1]:
current += c
else:
parts.append(current)
current = c
result = []
for part in parts:
if len(part) == n:
result.append(part)
return result
使用各种尺寸的字符串进行测试:
match("xxaaaayyybbbbbzzccccxx", 6) = []
match("xxaaaayyybbbbbzzccccxx", 5) = ["bbbbb"]
match("xxaaaayyybbbbbzzccccxx", 4) = ['aaaa', 'cccc']
match("xxaaaayyybbbbbzzccccxx", 3) = ["yyy"]
match("xxaaaayyybbbbbzzccccxx", 2) = ['xx', 'zz']
第一个循环基本上将文本分成若干部分,如:[“xx”,“aaaa”,“yyy”,“bbbbb”,“zz”,“cccc”,“xx”]。然后第二个循环测试这些部分的长度。最后,该函数仅返回具有当前长度的部分。我不是最擅长解释代码的,所以如果需要,任何人都可以自由地增强这种解释。
无论如何,我认为这样做了!
答案 6 :(得分:1)
为什么不给regexp引擎留下最好的东西 - 找到最长的相同符号串然后自己检查长度?
Perl:
my $str = 'xxaaaayyybbbbbzzccccxx';
while($str =~ /(.)\1{3,}/g){
if(($+[0] - $-[0]) == 4){ # insert here full match length counting specific to language
print (($1 x 4), "\n")
}
}
答案 7 :(得分:1)
在Java中,我们可以像下面的代码那样做
String test ="xxaaaayyybbbbbzzccccxx uuuuuutttttttt";
int trimLegth = 4; // length of the same characters
Pattern p = Pattern.compile("(\\w)\\1+",Pattern.CASE_INSENSITIVE| Pattern.MULTILINE);
Matcher m = p.matcher(test);
while (m.find())
{
if(m.group().length()==trimLegth) {
System.out.println("Same Characters String " + m.group());
}
}