好在,Ruby提供了更加灵活的分组捕获的引用控制。除了\N这种方式的反向引用,也可以通过\k<N>或\k<name>来引用,灵活之处在于\k<>支持递归层次的偏移,例如\k<name+0>表示取当前递归层次里的name分组捕获,\k<name+1>和\k<name-1>分别表示取当前递归层的下一层和上一层里的name分组捕获。
所以,在Ruby中改一下这个正则表达式就能正常工作:
/\A ( (.) \g<1> \k<2+0>|.) \Z/x =~ "abcba" #=> 0 /\A ( (.) \g<1> \k<2+0>|.) \Z/x =~ "abcbaa" #=> nil
当然,用命名捕获也是可以的:
/\A (?<i> (?<j>.) \g<i> \k<j+0>|.) \Z/x
最后,可以将上面的正则表达式改动一番。上面正则中,多选分支的.一直都是放在尾部的(放头部也没问题),但下面这种将多选分支和递归表达式嵌在一个分组内也是很常见的用法。下面这两种递归正则表达式是等价的。
/\A (?<i> (?<j>.) \g<i> \k<j+0>|.) \Z/x /\A (?<i> (?<j>.) (?:\g<i>|.) \k<j+0> ) \Z/x
(?:\g<i>|.)进行了分捕获的分组,分组将它们两绑定在一个组内,如果不分组将会出错,因为|的优先级太低。
不要滥用递归正则
虽然递归正则确实能解决一些特殊需求,但是能不用尽量不用,因为递归正则要配合量词来修饰递归表达式,这本身不是问题,但是递归表达式很多时候在分组内,而分组本身可能也会用量词去修饰,这样两个量词一结合,一不小心可能就出现大量的回溯,导致匹配效率疯狂下降。
已经演示过一个这样的现象,仅仅只是多了3个字符,匹配失败竟然需要多花费40多秒,而且随着字符的增多,匹配失败所需时间飙升的更快。这绝对是我们要去避免的。
所以,当写出来的递归正则表达式里又是分组、又是量词,看上去还"乱七八糟"的结合在一起,很可能会出现性能不佳的问题。这时候可能需要去调试优化,以便写出高性能的递归正则,但这可能会耗去大量的时间。
所以,尽量想其它方法来解决递归正则想要实现的匹配需求,或者只写看上去就很简单的递归正则。
总结
以上所述是小编给大家介绍的循序渐进掌握递归正则表达式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
您可能感兴趣的文章: