可以将上面的\g<0>看作是一个占位符,首先它可以匹配"abc and _xyz"或者def and _xyz这种格式的字符串,这里我用了_表示\g<0>占位符。递归一轮的话,它可以匹配"abc and def and _xyzxyz",这里又会继续递归下去,将没完没了。所以这里先将该正则匹配什么字符串的问题保留,稍后再回头分析。
事实上,/(abc|def) and \g<0>xyz/是错误的正则表达式,它会提示我们,递归没有终点:
/(abc|def) and \g<0>xyz/ #=>SyntaxError: never ending recursion
所以,使用递归正则必须要保证递归能够有终点。
保证正则递归的终点
怎么保证递归正则的终点呢?只要给\g<>这部分做一个量词的限定即可,比如:
\g<0>+ # 错误正则 \g<0>{3} # 错误正则 \g<0>{,3} # 错误正则 \g<0>* # 正确正则 \g<0>? # 正确正则 \g<0>{0} # 正确正则 pat|\g<0> # 正确正则 (\g<0>)* # 正确正则 (\g<0>)? # 正确正则 ...
\g<0>+表示递归至少1轮,但是这里已经错了,因为递归多次的时候,\g<0>这个占位符及其量词+将始终保留在最后一轮的结果中,于是导致无限递归。同理\g<0>{3}这种表示严格递归三次的方式也是错误的,因为递归第三次后仍然保留了\g<0>{3}占位符及其量词{3},这也将无限递归。
所以,只有\g<0>*和\g<0>?和\g<0>{0}和pat|\g<0>等这种能在量词数量选择意义上表示递归0次的方式才是正确的正则表达式语法,因为无论递归多少次,最后一次的占位符的量词都可以是0次,从而达到递归的终点,即停止递归。
所以,修改前面的正则表达式,假如使用?量词修饰\g<>:
/(abc|def) and \g<0>?xyz/
再探递归正则:递归正则匹配什么
回到之前遗留的问题,现在这个正确的递归正则表达式/(abc|def) and \g<0>?xyz/能匹配什么样的字符串呢?
按照之前的分析,它能匹配的字符串的模式类似于abc and _?xyz或者def and _?xyz。
如果量词?取0次,那么该递归正则匹配的是"abc and xyz"或"def and xyz":
reg = /(abc|def) and \g<0>?xyz/ reg =~ "abc and xyz" #=> 0 reg =~ "def and xyz" #=> 0
如果量词?取1次,那么该递归一轮后的正则模式为abc and abc and _?xyzxyz,其中任何一个"abc"替换成"def"都是满足条件的。那么这里又有了\g<>量词的次数选择问题。
假如这里量词?取0次,也就是从开始到现在总体递归了一轮。那么该递归正则匹配到是:
reg = /(abc|def) and \g<0>?xyz/ reg =~ "abc and abc and xyzxyz" #=> 0 reg =~ "abc and def and xyzxyz" #=> 0 reg =~ "def and def and xyzxyz" #=> 0 reg =~ "def and abc and xyzxyz" #=> 0
如果递归一轮后的量词?继续取1次呢?那么下一轮递归仍将会有量词次数选择的问题。
至此,应该理解了递归正则的基本匹配方式。不过这里使用的\g<0>递归还很基础,下面将继续逐步深入。
深入递归(1):括号分组内的\g
前面的递归示例中是将能表示递归的表达式\g<0>部分放在分组的外面,这种情况下,只有\g<0>这种形式才能算是递归,如果是\g<1>或\g<name>,就算不上是递归,充其量也就是个表达式的调用。
但是,当需要使用递归正则来解决问题的时候,递归表达式往往是在分组内部而不是在分组外部的。所以,前面解释的递归方式其实非常少见。于是,要使用递归正则,还得继续深入探索。
首先看一个非常简单的组内递归正则表达式:
/(abc\g<1>?xyz)+/
这个表达式中,进行了一个分组捕获,这个分组首先匹配abc字符,然后在分组捕获内使用了表达式\g<1>?(注意这个?是不能少的,当然?也可以换成其它的前面解释过的量词),紧随其后的是匹配字符xyz。由于这里的\g<1>?放在1号索引对应的分组捕获的内部,所以就形成了一个递归的正则表达式。
问题是,这个正则表达式能匹配什么样的字符串呢?要学会递归正则表达式,必须会分析它能够匹配什么类型的字符串。
仍然,以占位符的方式来表示\g<1>,那么该递归正则表达式匹配的字符串模式为:"abc_?xyz" * N,这个* N表示重复N次,因为这种表达式的括号分组外面有一个+符号。
如果量词?选择为0次,也就是不进行递归,则匹配字符串"abcxyz" * N: