正则表达式子程序在Npp中工作正常,但在PCRE中行为奇怪

4
尝试学习正则表达式子程序。我制作了这个正则表达式来匹配IP地址。它在记事本++中可以工作,但是当我在网上的PCRE测试器中尝试时,它只能匹配最多在最后一组中有2个数字的IP。你能帮我理解为什么吗?
\b((\d{1,2}|[01]\d{2}|2[0-4]\d|25[0-5])\.){3}(?2)\b 

在NPP中的示例 "192.168.0.219 192.168.0.21" 中,我有2个匹配项,而PCRE(regex101.com)仅匹配第二个地址。

请提供有效和无效输入的示例以及预期的匹配/不匹配情况。 - Poul Bak
在NPP中,我有两个匹配项:"192.168.0.219"和"192.168.0.21"。然而,在PCRE(https://regex101.com/)中,只匹配到了第二个地址。 - Antoni Gual Via
1个回答

3
Notepad++使用boost进行正则表达式。请看这里:Notepad++使用哪个正则表达式引擎?。这可能解释了差异。
问题在于这段代码\d{1,2},在递归时不会按预期工作(在PCRE上)。在非递归情况下,您必须在数字后找到一个点。
但由于递归目标是第二组,因此您“进入”递归模式,找到\d{1,2}(从219中的21),然后结束递归。然后,当退出时,您应该找到\b,但您没有找到它(您找到了一个9),因此失败。
也许增强引擎在进入递归之前会考虑整个表达式。或者它有一个不同的回溯系统,允许回溯递归并为选项组中的其他选项重新评估递归。最终,不同的实现导致不同的结果。
为使两者工作相同,您可以使用以下内容:

\b(([01]\d{2}|2[0-4]\d|25[0-5]|\d{1,2})\.){3}(?2)\b

也就是说,将\d{1,2}放在最后一个选项。

演示

一般来说,对于选项组(比如,(aaa|aa|a)),按照最长模式优先的顺序排序是一个好习惯(如果存在重叠)。

作为替代方案,如果您想保持组内相同的顺序,可以使用:

\b((\d{1,2}(?!\d)|[01]\d{2}|2[0-4]\d|25[0-5])\.){3}(?2)\b

我们在\d{1,2}后面添加了一个负向预查,确保该位置后面没有数字。

谢谢,朱利奥。非常清晰的解释,现在 PCRE 的行为对我来说已经变得合乎逻辑了。现在我的问题应该是为什么它能在 Notepad++ 中工作... - Antoni Gual Via
它可以在Notepad+上工作,因为Boost是一种不同的正则表达式引擎,具有不同的实现。Boost可能具有不同的回溯机制。例如,一旦它失败了219,它可能会回溯到(?2)并重新测试下一个选项/ s([01]\d{2} =then=> 2[0-4]\d)。我并不是说这就是真正发生的事情,因为我不知道实现方式。 - Julio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接