PCRE 正则表达式在移动到子例程时表现不同

PCRE regex behaves differently when moved to subroutine

使用 PCRE v8.42,我试图将一个正则表达式抽象为一个命名的子例程,但是当它在一个子例程中时,它的行为似乎有所不同。

这输出 10/:

echo '10/' | pcregrep '(?:0?[1-9]|1[0-2])\/' 

这没有输出:

echo '10/' | pcregrep '(?(DEFINE)(?<MONTHNUM>(?:0?[1-9]|1[0-2])))(?&MONTHNUM)\/'

这两个正则表达式不等价吗?

在 PCRE2 prior to 10.30, all subroutine calls are always treated as atomic groups. Your (?(DEFINE)(?<MONTHNUM>(?:0?[1-9]|1[0-2])))(?&MONTHNUM)\/ regex is actually equal to (?>0?[1-9]|1[0-2])\/. See this regex demo 版本中,10/ 与预期不匹配。

没有匹配,因为 0?[1-9]10/ 中的 1 匹配,并且由于不允许回溯,因此未测试(“输入”)第二个备选方案,并且整场比赛失败,因为 1.

之后没有 /

您需要确保较长的备选方案排在第一位:

(?(DEFINE)(?<MONTHNUM>(?:1[0-2]|0?[1-9])))(?&MONTHNUM)/

regex demo。请注意,在 pcregrep 模式中,您不需要转义 /.

或者,您可以使用 PCRE2 v10.30 或更新版本。