递归子模式似乎不适用于交替
Recurse subpattern doesn't seem to work with alternation
我想用逗号分隔的数字匹配字符串。简而言之,我最多想匹配 1-16 范围内的 8 个数字。所以字符串 1,2,3,4,5,6,7,8
可以,而 1,2,3,4,5,6,7,8,9
不行,因为它有 9 个数字。 16
也可以,但 17
不行,因为 17 不在范围内。
我尝试使用这个正则表达式 ^(?:(?:[1-9]|1[0-6]),){0,7}(?:[1-9]|1[0-6])$
它工作正常。我使用交替来匹配 1-16 的数字,然后我使用 0..7 重复,末尾有逗号,然后相同,末尾没有逗号。但是我不喜欢子模式的重复,所以我尝试 (?1)
递归第一个捕获组。我的正则表达式看起来像 ^(?:([1-9]|1[0-6]),){0,7}(?1)$
。但是,当最后一个数字有两个字母 (10-16) 时,这不会产生匹配。它匹配 1,1
,但不匹配 1,10
。我不懂为什么。
我创建了一个问题示例。
https://regex101.com/r/VkuPqP/1
在调试器中,当模式递归时,我看到引擎不尝试组中的第二次交替。我希望它能起作用。问题出在哪里?
发生这种情况是因为 PCRE 中的 regex subroutines 是原子的。
您的正则表达式可以重写为 ^(?:([1-9]|1[0-6]),){0,7}(?>[1-9]|1[0-6])$
,参见 its demo。 (?>...|...)
将不允许回溯到该组中,因此如果第一个分支 "wins" (如您的示例所示),则在下一个子模式失败时不会尝试后续分支(此处,$
匹配 1
后无法匹配字符串的结尾 - 它后面跟着 0
)。
在这种情况下,您可以交换备选方案,较长的优先:
^(?:(1[0-6]|[1-9]),){0,7}(?1)$
参见regex demo。
一般来说,最佳做法是组中的每个备选方案必须匹配字符串中的不同位置。它们不应在相同位置匹配。
如果您无法重写交替组以使每个替代组都匹配字符串中的唯一位置,则您应该重复该组而不使用正则表达式子例程。
我想用逗号分隔的数字匹配字符串。简而言之,我最多想匹配 1-16 范围内的 8 个数字。所以字符串 1,2,3,4,5,6,7,8
可以,而 1,2,3,4,5,6,7,8,9
不行,因为它有 9 个数字。 16
也可以,但 17
不行,因为 17 不在范围内。
我尝试使用这个正则表达式 ^(?:(?:[1-9]|1[0-6]),){0,7}(?:[1-9]|1[0-6])$
它工作正常。我使用交替来匹配 1-16 的数字,然后我使用 0..7 重复,末尾有逗号,然后相同,末尾没有逗号。但是我不喜欢子模式的重复,所以我尝试 (?1)
递归第一个捕获组。我的正则表达式看起来像 ^(?:([1-9]|1[0-6]),){0,7}(?1)$
。但是,当最后一个数字有两个字母 (10-16) 时,这不会产生匹配。它匹配 1,1
,但不匹配 1,10
。我不懂为什么。
我创建了一个问题示例。
https://regex101.com/r/VkuPqP/1
在调试器中,当模式递归时,我看到引擎不尝试组中的第二次交替。我希望它能起作用。问题出在哪里?
发生这种情况是因为 PCRE 中的 regex subroutines 是原子的。
您的正则表达式可以重写为 ^(?:([1-9]|1[0-6]),){0,7}(?>[1-9]|1[0-6])$
,参见 its demo。 (?>...|...)
将不允许回溯到该组中,因此如果第一个分支 "wins" (如您的示例所示),则在下一个子模式失败时不会尝试后续分支(此处,$
匹配 1
后无法匹配字符串的结尾 - 它后面跟着 0
)。
在这种情况下,您可以交换备选方案,较长的优先:
^(?:(1[0-6]|[1-9]),){0,7}(?1)$
参见regex demo。
一般来说,最佳做法是组中的每个备选方案必须匹配字符串中的不同位置。它们不应在相同位置匹配。
如果您无法重写交替组以使每个替代组都匹配字符串中的唯一位置,则您应该重复该组而不使用正则表达式子例程。