3

我正在尝试学习正则表达式中的递归,并对 PCRE 风格中的概念有一个基本的了解。我想打破一个字符串:

Geese (Flock) Dogs (Pack) 

进入:

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)

我知道两个正则表达式都不能做到这一点,但我对第一个模式有效而第二个模式不起作用的原因更加好奇。

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)

这是我最接近的模式,但中间组:Dogs (Pack) 变为 Group 0。

((.*?)(\(\w{1,}\)))((.*?)(\g<3>))*
4

1 回答 1

1

请注意 PCRE 中的递归级别是原子的。一旦这些模式找到匹配项,它们就永远不会重试。

请参阅递归和子例程调用可能是原子的,也可能不是原子的

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

您的第二个模式,在第一个递归级别,看起来像

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

演示。也就是说,\g<2>是,那么(?>.*?),不是.*?。这意味着,在((.*?)(\(\w{1,}\)))模式Geese (Flock)match 之后,正则表达式引擎尝试(?>.*?)(?>\(\w{1,}\)). 由于没有(after ),正则表达式返回它消耗的内容。

至于第二个问题,这是一个普遍的问题。使用 PCRE 正则表达式不可能获得任意数量的捕获,因为在重复捕获的情况下,只有最后一个捕获的值存储在组缓冲区中。结果数组中的子匹配数不能多于正则表达式模式内的捕获组数。有关更多详细信息,请参阅重复捕获组与捕获重复组

于 2018-08-19T07:13:35.207 回答