正则表达式递归:第N个子模式

3
我正在尝试学习正则表达式中的递归,对 PCRE 版本的概念有基本的理解。我想要分割一个字符串:
Geese (Flock) Dogs (Pack) 

into:

Full Match: Geese (Flock) Dogs (Pack) 
Group 1: Geese (Flock)
Group 2: Geese
Group 3: (Flock)
Group 4: Dogs (Pack)
Group 5: Dogs
Group 6: (Pack)

我知道两个正则表达式都无法实现这个功能,但我更好奇的是为什么 first 这种模式可以工作,而 second 不行。
Pattern 1: ((.*?)(\(\w{1,}\)))((.*?)(\g<3>))*
Pattern 2: ((.*?)(\(\w{1,}\)))((\g<2>)(\g<3>))*

此外,例如,如果您正在处理一个长字符串,并且有一个模式重复出现,那么是否可以不编写与正则表达式分开的循环语句,而是持续扩展完整匹配并逐步增加组?
Full Match: Geese (Flock) Dogs (Pack) Elephants (Herd) 
Group 1: Geese (Flock)
Group 2: Geese
Group 3: (Flock)
Group 4: Dogs (Pack)
Group 5: Dogs
Group 6: (Pack)
Group 7: Elephants (Herd)
Group 8: Elephants 
Group 9: (Herd)

这是我找到的最接近的模式closest,但中间的组别:狗(群)变成了0组。
((.*?)(\(\w{1,}\)))((.*?)(\g<3>))*

关于 Q2,重复捕获组只保留最后匹配的出现,这是一个在 SO 上常见的问题。Q1 很容易回答,但需要时间来解释:在 PCRE 中,递归级别是原子的 - Wiktor Stribiżew
另外,请参考此线程,它可能是一个重复的原因。 - Wiktor Stribiżew
谢谢,我会仔细阅读的。 - rsylatian
关于第一部分,我已经查看了链接和您的SO答案,但仍然不太明白。我知道原子性是指一旦找到匹配项,就不会重新进入它。那么我在这里做错了吗?这实际上与第一组的使用有关吗?还是与组的位置有关?或者两者都有关系? - rsylatian
如果您不介意的话,请帮我翻译一下吧?不需要太深入,一旦我理解了这个概念,我会再重新阅读其他内容的。谢谢。 - rsylatian
显示剩余2条评论
1个回答

1
注意,PCRE中的递归级别是原子的。一旦这些模式找到匹配项,它们就不会被重新尝试。
参见递归和子例程调用可能是原子的也可能不是:

PerlRuby如果递归后的正则表达式失败,则回溯到递归中。他们根据需要尝试递归的所有排列方式,以允许正则表达式的其余部分匹配。 PCRE将递归视为原子操作。在递归期间,PCRE会正常回溯,但一旦递归匹配成功,即使正则表达式的其余部分无法匹配,它也不会尝试任何进一步的递归排列。结果是,Perl和Ruby可能会找到PCRE无法找到的正则表达式匹配项,或者Perl和Ruby可能会找到不同的正则表达式匹配项。

你的第二个模式,在第一次递归层级中,会看起来像这样:

((.*?)(\(\w{1,}\)))(((?>.*?))((?>\(\w{1,}\))))*
                     ^^^^^^^  ^^^^^^^^^^^^^^

请参见演示。也就是说,\g<2> 然后是 (?>.*?),而不是 .*?。这意味着在模式 ((.*?)(\(\w{1,}\))) 匹配了 Geese(Flock) 后,正则表达式引擎尝试与 (?>.*?) 匹配,发现它是一个不必消耗任何字符的惰性模式,跳过它(并且永远不会回到这个模式),然后尝试与 (?>\(\w{1,}\)) 匹配。由于在 ) 后没有 (,因此正则表达式返回其所消耗的内容。
关于第二个问题,这是一个常见的问题。使用PCRE正则表达式无法获取任意数量的捕获结果,因为在重复捕获的情况下,仅最后一个捕获值会存储在组缓冲区中。在结果数组中不能有比正则表达式模式中捕获组的数量更多的子匹配项。详见重复捕获组与捕获重复组

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接