接触过程序的朋友可能都遇到过成对的各种括号吧,这些括号常常相互嵌套,而且嵌套的层次数目无法确定。试想一下如果想提取一段程序里用括号括起的一段代码,这里面很可能包含了层次数目不定的其它括号对,用正则表达式该如何完成?
在Perl 5.6之前这的确有点困难,不过从Perl 5.6之后,引入了递归正则表达式,这个问题得到了解决。通常在正则表达式里用“(?R)”表示一个对自己的引用,下面让我们看看用什么正则表达式来解决刚才提出的问题。
/\( ( (?>[^()]+) | (?R) )* \)/x
现在让我们来分析这个模式的含义,这里使用了“x”模式修正符,以便可以在模式中加入空格以方便阅读。
模式的开头是匹配第一个左圆括号,然后我们需要捕获的子模式,注意,字模式后面跟了量词“*”,表示此模式可以重复0到多次。最后是一个结束圆括号。现在我们分析子模式( (?>[^()]+) | (?R) )的内容。这是一个分支子模式,表示模式可以有两种情况,第一种是(?>[^()]+),这是一个一次性子模式,代表一个以上的非括号字符,另一种情况是| (?R),也即对正则表达式自己的递归调用——\( ( (?>[^()]+) | (?R) )* \),又寻找一个左圆括号,开始查找一对嵌套的圆括号包含的内容。
分析到这里,这个正则表达式的含义已经基本清楚,但你注意到没有,这里为什么要使用一次性子模式(?>[^()]+)来查找非括号字符串?
事实上,由于递归的层次是无限的,这种处理非常必要,特别是遇到不匹配的字符串时,它不会让你陷入长时间的等待。考虑一下下面这个目标字符串,
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
在得出不匹配的最终结果前,如果不使用一次性子模式,解析器将尝试每一种可能的方法来分割目标字符串,这将浪费大量的时间。
原文出自【比特网】,转载请保留原文链接:http://biz.chinabyte.com/382/2225382.shtml
评论