我有一个正则表达式,可以多种重叠的方式匹配字符串。但是,它似乎只捕获字符串中的一个可能的匹配,我如何获得所有可能的匹配?我试过finditer但没有成功,但也许我错了。
我想解析的字符串是:
foo-foobar-foobaz
我正在使用的正则表达式是:
(.*)-(.*)
>>> s = "foo-foobar-foobaz"
>>> matches = re.finditer(r'(.*)-(.*)', s)
>>> [match.group(1) for match in matches]
['foo-foobar']
我想要比赛(foo和foobar-foobaz),但似乎只能获得(foo-foobar和foobaz)。
答案 0 :(得分:5)
没问题:
>>> regex = "([^-]*-)(?=([^-]*))"
>>> for result in re.finditer(regex, "foo-foobar-foobaz"):
>>> print("".join(result.groups()))
foo-foobar
foobar-foobaz
通过将第二个捕获括号放在lookahead assertion中,您可以捕获其内容,而不会在整体匹配中使用它。
我还使用[^-]*
代替.*
,因为该点也与您可能不想要的分隔符-
匹配。
答案 1 :(得分:2)
这不是正则表达式引擎往往能够做到的。我不知道Python是否可以。 Perl可以使用以下内容:
local our @matches;
"foo-foobar-foobaz" =~ /
^(.*)-(.*)\z
(?{ push @matches, [ $1, $2 ] })
(*FAIL)
/xs;
使用以下技术可以使用多种语言的正则表达式引擎解决此特定问题:
my @matches;
while ("foo-foobar-foobaz" =~ /(?=-(.*)\z)/gsp) {
push @matches, [ ${^PREMATCH}, $1 ];
}
(${^PREMATCH}
指的是正则表达式匹配之前的内容,而$1
指的是第一个()
匹配的内容。)
但是您可以在正则表达式引擎之外轻松解决这个特定问题:
my @parts = split(/-/, "foo-foobar-foobaz");
my @matches;
for (1..$#parts) {
push @matches, [
join('-', @parts[0..$_-1]),
join('-', @parts[$_..$#parts]),
];
}
很抱歉使用Perl语法,但应该能够理解。翻译到Python欢迎。
答案 2 :(得分:1)
如果你想检测重叠的匹配,你必须自己实现它 - 基本上,对于一个字符串foo
i
foo[i+1:]
如果您使用任意长度的捕获组(例如(.*)
)会变得更加棘手,因为您可能不希望foo-foobar
和oo-foobar
都匹配,所以你会必须做一些额外的分析才能使i
比每场比赛更+1
更远;你需要将它移动到第一个捕获组的值的整个长度,加上一个。