我有一个像这样的简单正则表达式:
@123(?:(?:(?P<test>[\s\S]*)456(?P<test1>(?P>test))789))@
它应匹配以下字符串:
123aaaa456bbbb789
但它没有。
但是,如果我用正则表达式的直接副本替换子例程引用:
@123(?:(?:(?P<test>[\s\S]*)456(?P<test1>[\s\S]*)789))@
然后它完美无缺。
我无法弄清楚为什么通过群组名称引用模式不起作用。
答案 0 :(得分:2)
这里的要点是[\s\S]*
是一个*
量化的子模式,允许正则表达式引擎在后续子模式无法匹配时回溯,但 PCRE中的递归调用是原子,即当引擎用(?P>test)
抓取任何0+字符时引擎无法回溯,这就是模式无法匹配的原因。
简而言之,@123(?:(?:(?P<test>[\s\S]*)456(?P<test1>(?P>test))789))@
模式可以重写为
@123(?:(?:(?P<test>[\s\S]*)456(?P<test1>[\s\S]*+)789))@
^^
且[\s\S]*+
已匹配789
,引擎无法回溯以匹配789
模式部分。
请参阅PCRE docs:
在PCRE中(与Python类似,但与Perl不同),递归子模式调用始终被视为原子组。也就是说,一旦它匹配了一些主题字符串,它就永远不会被重新输入,即使它包含未经验证的替代品并且随后存在匹配失败。
不知道为什么他们在这里提到Python,因为re
不支持递归(除非他们指的是PyPi正则表达式模块)。
如果您正在寻找解决方案,可以使用(?:(?!789)[\s\S])*
tempered greedy token代替[\s\S]*
,它只会匹配任何字符,如果它没有启动789
char序列(因此,无需回溯以适应789
):
123(?:(?:(?P<test>(?:(?!789)[\s\S])*)456(?P<test1>(?P>test))789))
^^^^^^^^^^^^^^^^^^
请参阅this regex demo。