重用分支重置组并不匹配所有替代方案

Reusing branch reset group doesn't match all the alternatives

我正在尝试使用下面的 RegEx 验证 IPv4 地址

^((?|([0-9][0-9]?)|(1[0-9][0-9])|(2[0-5][0-5]))\.){3}(?2)$

在大多数情况下,正则表达式在 IP 地址的第三个八位字节之前工作正常。但有时在最后一个八位位组中,它只匹配 Branch Reset Group 中的第一个备选组,而完全忽略其他交替组。我知道分支重置组中的所有替代方案都指的是同一个捕获组。我尝试了重用 中描述的捕获组的建议。它部分起作用了。

原因是(?2) regex subroutine recurses the first capturing group pattern with the ID 2、([0-9][0-9]?)。如果匹配失败($ 要求紧跟其后的字符串结尾),则开始回溯,最终匹配失败。

递归一组模式的正确方法是避免使用 branch reset group 并将所有备选方案捕获到将被递归的 单个 捕获组中:

^(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?1)$
//  |____________ Group 1 _______________|        \_ Regex subroutine

参见regex demo

注意八位位组模式有点不同,它取自 How to Find or Validate an IP Address。您的八位字节模式是错误的,因为 2[0-5][0-5]200255 之间以 678 和 [= 结尾的数字不匹配20=].

此页面上有关于此行为的解释:

https://www.pcre.org/original/doc/html/pcrepattern.html#SEC15

文档指出:

a subroutine call to a numbered subpattern always refers to the first one in the pattern with the given number.

使用该页面上的示例:

(?|(abc)|(def))(?1)

Inside a (?| group, parentheses are numbered as usual, but the number is reset at the start of each branch.

数字将如下所示

(?|(abc)|(def))
   1     1

这将匹配

abcabc
defabc
abcabc

但是不匹配

defdef

它不匹配 defdef 因为该模式将匹配第一个 def,但随后的 (?1) 将仅匹配第一个编号的子模式 (abc)

看到一个regex demo.