正则表达式高级技巧及实例详解(4)
5. 最小组团(Atomic Groups)
最小组团是无捕捉的特殊正则表达式分组。通常用来提高正则表达式的效能,也能用于消除特定匹配。一个最小组团可以用(?>pattern) 来定义,其中pattern是匹配式。
/(?>his|this)/
当正则引擎针对最小组团进行匹配时,它会跳过组团内标记的回溯位置。以单词“smashing”为例,当用上面的正则表达式匹配时,正则引擎会先尝试在“smashing”里寻找“his”。显然,找不到任何匹配。此时,最小组团就发挥作用了:正则引擎会放弃所有回溯位置。也就是说,它不会尝试再从“smashing”里查找“this”。为什么要这样设置?因为“his”都没有返回匹配结果,包含有“his”的“this”当然就更匹配不了了!
上面的例子并没有什么实用性,我们用/t?his?/
也能达到效果。再看看下面的例子:
/\b(engineer|engrave|
end
)\b/
如果把“engineering”拿去匹配,正则引擎会先匹配到“engineer”,但接下来就遇到了字词边界,\b
,所以匹配不成功。然后,正则引擎又会尝试在字串里寻找下一个匹配内容:engrave。匹配到eng的时候,后面的又对不上了,匹配失败。最后,尝试“end”,结果同样是失败。仔细观察,你会发现,一旦engineer匹配失败,并且都抵达了字词边界,“engrave”和“end”这两个词就已经不可能匹配成功了。这两个词都比engineer短小,正则引擎不应该再多做无谓的尝试。
/\b(?>engineer|engrave|
end
)\b/
上面的替代写法更能节省正则引擎的匹配时间,提高代码的工作效率。
6. 递归(Recursion)
递归(Recursion)用于匹配嵌套结构,例如括弧嵌套, (this (that)),HTML标签嵌套<div>
<div></div>
</div>
。我们使用(?R)
来代表递归过程中的子模式。下面是一个匹配嵌套括弧的例子:
/\(((?>[^()]+)|(?R))*\)/
最外层使用了反义符的括号“\(
”匹配嵌套结构的开端。然后是一个多选项操作符( * | * )
,可能匹配除括号外的所有字符 “(?>[^()]+)
”,也可能是通过子模式“(?R)
”来再次匹配整个表达式。请注意,这个操作符会尽量多地匹配所有嵌套。
递归的另一个实例如下:
/<([\w]+).*?>((?>[^<>]+)|((?R)))*<\/\1>/
以上表达式综合运用了字符分组,贪婪操作符、回溯,以及最小化组团来匹配嵌套标签。第一个括弧内分组([w]+)
匹配出标签名,用于接下来的应用。若找到这尖括号样式的标签,则尝试寻找标签内容的剩余部分。下一个括弧括起来的子表达式和上一个实例非常相似:要么匹配不包括尖括号的所有字符 ?>[^<>]+
,要么递归匹配整个表达式(?R)
。表达式最后的</1>
代表闭合标签。
(责任编辑:IT教学网)