正则表达式子例程在 Npp 中工作,但在 PCRE 中表现异常

Regex subroutine works in Npp but behaves strangely in PCRE

正在尝试学习 Regex 子例程。我制作了这个 Regex 来匹配 IP 地址。它在 Notepad++ 中工作,但是当我在网络中的 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) 仅匹配第二个地址。

Notepad++ 使用 boost for regex. See here: Which regex engine does Notepad++ use?。所以这可以解释差异。

问题是这一段 \d{1,2},它不会像您预期的那样使用递归(在 PCRE 上)工作。在非递归的情况下,你被迫在数字后面找到一个点。

但是由于递归目标组 2,您在递归模式上 'enter',您找到 \d{1,2}(来自 21921)并结束递归。然后,当退出时你应该找到 \b,但你没有(你找到 9),所以你失败了。

也许boost引擎在进入递归之前考虑了整个表达式。或者它可能有一个不同的回溯系统,允许回溯递归并为其他选项组再次重新评估递归。最后,不同的实现会导致不同的结果。

为了让这两个东西一样工作,你可以使用这个:

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

也就是说,您将 \d{1,2} 作为最后一个选项。

Demo

一般来说,好的做法 对选项组进行排序(比如,假设 (aaa|aa|a)),这样最长的模式首先出现(如果某些重叠是可能的)

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

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

(我们在\d{1,2}后面加了个负数,后面一定不能有数字)