无限递归
无限递归
正则表达式,例如(?R)?z
或a?(?R)?z
或a|(?R)z
在进入递归前没有任何的匹配,这种情况会导致无限递归。如果正则表达式引擎在不推进文本的情况下到达了递归,则下一个递归将在不推进文本的情况下再次到达递归。对于第一个正则表达式,这种情况会在匹配开始时立即发生。对于剩下的其他两个,当没有字母a匹配的时候,无限递归就开始产生了。
JGsoft V2和Boost 1.64将前两个正则表达式视为语法错误,因为它们总是导致无限递归。他们允许第三个正则表达式,因为它能匹配字符a。Ruby 1.9和更高版本,PCRE的所有版本以及PCRE2 10.20和先前版本将造成无限递归的所有三种形式都视为语法错误。Perl,PCRE2 10.21和更高版本以及Boost 1.63和先前版本允许所有这三种形式。
循环无限子例程调用
子例程调用也可能导致无限递归。所有正则表达式引擎都以相同的方式处理((?1)?z)
或(a?(?1)?z)
或(a|(?1)z)
中的潜在无限递归。
但是,如果子例程调用的组具有另一个子例程调用,而该子例程调用了第一个子例程调用的父组,则这些子例程调用本身并不具有递归性。当子例程调用被迫循环时,这也会导致无限递归。编译正则表达式时,检测此类循环调用比检查直接无限递归要复杂得多。只有JGsoft V2和Ruby 1.9及更高版本才能检测到此错误并将其视为语法错误。所有其他引擎都允许使用这些正则表达式。
错误和崩溃
当发生无限递归时,无论是直接递归还是循环中的子例程调用,JGsoft V2,Perl和PCRE2都会将其视为匹配错误,从而中止整个匹配尝试。Boost 1.64通过不尝试递归并假定递归失败来处理此问题。如果递归是可选的,则Boost 1.64可能会在其他引擎抛出错误的地方找到匹配项。
当发生无限递归时,Boost1.63和更早版本以及PCRE 8.12和更早版本都会发生崩溃。由于它们基于较旧的PCRE版本,这也会影响Delphi最高版本XE6和PHP版本5.4.8。
无休止的递归
正则表达式如a(?R)z
将导致无穷递归。因为正则表达式中的递归不是可选的,并且不具有选择项。这样的正则表达式永远找不到匹配项。当a匹配时,正则表达式引擎将尝试递归。如果可以匹配另一个a,则必须再次尝试递归。最终,a将用尽所有字母以进行匹配。递归然后失败。因为它不是可选的,所以正则表达式无法匹配。
JGsoft V2和Ruby在编译正则表达式时会检测到这种情况。他们将无穷递归标记为语法错误。Perl,PCRE,PCRE2和Boost无法检测到无穷递归。他们只是简单地进行了匹配,并且宣告没有找到匹配项。