上一节记录了主要的一些元字符集,算是刚刚入了门。这一节主要介绍一些稍微需要动脑筋的东西。
分组实际上就是个对括号,用处就是将一个匹配串当成一个整体来看,用于改变匹配的优先级。比如我们要匹配“abcabcabcabc”,就可以这样匹配:(abc){4}
。
在分组的基础上,我们就可以进行后向引用。所谓后向引用,就是将之前匹配到的字符串记录下来,供后来继续用,提高表达式的效率。
具体用法是,系统会给表达式中所有的分组标上序号,从1开始。接下来每当希望用到之前分组的内容时,只需要调用"i" 其中i就是分组对应的序号。
比如(abc)11213
注:目测这样写的话,组数不能超过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次以上,但尽可能少重复 |
当然正则表达式在不同的平台上还有其他不同的功能,比如会有一些选项来优化匹配方式,或者是平衡组、递归匹配这些复杂的东西。这些遇到了再行了解。