正则表达式为什么在这里有两个组时负面预测不起作用

时间:2013-10-16 02:13:13

标签: java javascript regex negative-lookahead

当我尝试这个正则表达式时

\"(\S\S+)\"(?!;c)

在这个字符串上“MM:”; d 它符合我想要的匹配

并且在此字符串上“MM:”; c 它与所需内容不匹配。

但是当我添加第二组时,通过移动该组中的分号并使用|

使其成为可选项
\"(\S\S+)\"(;|)(?!c)

这个字符串“MM:”; c 当我预期它不喜欢之前它匹配。

我在Java上尝试了这个,然后在Javascript上使用Regex工具debuggex:

This link contains a snippet of the above

我做错了什么?

注意|因此没有必要有分号。在我放c的例子中,它只是一个单词的例子中的替代品,这就是我使用负向前瞻的原因。

遵循Holgers对使用占有量词的回应,

\"(\S\S+)\";?+(?!c)

有效,here is a link to it on RegexPlanet

2 个答案:

答案 0 :(得分:2)

我相信正则表达式会尽其所能找到匹配;因为你的表达式表示分号可以是可选的,所以它发现它可以匹配整个表达式(因为如果第一组没有使用分号,那么负向前瞻就会变成“不匹配”。这与正则表达式的递归方式:它一直试图找到一个匹配...

换句话说,过程如下:

MM:" - matched
(;|) - try semicolon? matched
(?!c) - oops - negative lookahead fails. No match. Go back
(;|)  - try nothing. We still have ';c' left to match
(?!c) - negative lookahead not matched. We have a match 

更新(根据您的评论)。以下代码可能会更好:

\"(\S\S+)\"(;|)((?!c)|(?!;c))

Regular expression visualization

Debuggex Demo

答案 1 :(得分:1)

问题是你不想在正则表达式的意义上使分号成为可选的。一个可选的分号意味着匹配器可以尝试两者,匹配或不匹配。因此,即使分号在那里,匹配器也可以忽略它为该组创建一个空匹配,让前瞻成功。

但是如果它在那里你想要使用分号,所以不允许它用于满足负前瞻。使用Java的正则表达式引擎非常简单:使用;?+

这被称为“占有量词”。与?一样,分号不需要在那里但是如果它在那里它必须匹配且不能被忽略。所以正则表达式引擎已经没有其他选择了。

如果您需要分组中的分号,整个模式看起来像\"(\S\S+)\";?+(?!c)\"(\S\S+)\"(;?+)(?!c)