Mythsman


乐极生悲,苦尽甘来。


正则表达式基础(2)

上一节记录了主要的一些元字符集,算是刚刚入了门。这一节主要介绍一些稍微需要动脑筋的东西。

分组捕获与后向引用

分组实际上就是个对括号,用处就是将一个匹配串当成一个整体来看,用于改变匹配的优先级。比如我们要匹配“abcabcabcabc”,就可以这样匹配:(abc){4}

在分组的基础上,我们就可以进行后向引用。所谓后向引用,就是将之前匹配到的字符串记录下来,供后来继续用,提高表达式的效率。

具体用法是,系统会给表达式中所有的分组标上序号,从1开始。接下来每当希望用到之前分组的内容时,只需要调用"i" 其中i就是分组对应的序号。

比如(abc)1$12$13$14 就可以匹配“abc1abc2abc3abc4”了。

注:目测这样写的话,组数不能超过9,毕竟“”这个东西只能作用于一个字符。

零宽断言

这个是用来匹配一个位置而不是一个字符串的比如 ( $ 和 ^ ) ,所以叫零宽。他规定了当前的位置需要满足某些条件,或者不能够满足某些条件。也是非常有用处的一个东西。

1、(?=exp)        零宽度正预测先行断言

它断言自身出现的位置的后面能匹配表达式exp。比如bw+(?=ingb),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。

2、(?<=exp)     零宽度正回顾后发断言

它断言自身出现的位置的前面能匹配表达式exp。比如(?<=bre)w+b 会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。

3、(?!exp)    零宽度负预测先行断言

它断言此位置的后面不能匹配表达式exp。例如:d{3}(?!d) 匹配三位数字,而且这三位数字的后面不能是数字;b((?!abc)w)+b 匹配不包含连续字符串abc的单词。
4、(?<!exp)    零宽度负回顾后发断言

它断言此位置的前面不能匹配表达式exp:(?<![a-z])d{7} 匹配前面不是小写字母的七位数字。

注释

由于正则一向比较精炼,所以注释还是很有必要的。

我们可以用语法(?#comment)来包含注释。例如:2[0-4]d(?#200-249)|25[0-5](?#250-255)|[01]?dd?(?#0-199)

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是在满足匹配关系的情况下匹配尽可能多的字符。这被称为贪婪匹配,也是默认的匹配方式。

然而有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号'?'。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)ab(第四到第五个字符)

懒惰限定符
代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

当然正则表达式在不同的平台上还有其他不同的功能,比如会有一些选项来优化匹配方式,或者是平衡组、递归匹配这些复杂的东西。这些遇到了再行了解。