书接上回,在理解了正则的作用和基本规则之后,我们可以开始解读正则表达式了。
很多同学在看别人写的正则时,会看不懂,很晕,我刚开始也一样。其实正则的读法和写法的精髓在“拆分”与“组合”,跟炼金术似的,因为正则表达式是由一系列元素按照一定的方法构成的,我根据他们的特性,主要分为以下6类:
- 元字符-量词类
- 元字符-特殊类
- 转义类
- 特征修饰符Pattern modifier
- 捕获子组&引用
- 非捕获子组:一次性子组&断言
这样的分类是帮助你理解的,正则是工具,是拿来用的,不用背。我们需要理解他们的构成方法,然后对他们进行拆分和组合。
元字符-量词类Repetition
我们先来认识一些正则基本的元素。正则中有一些被赋予特殊涵义的字符被成为“元字符”,使其不再单纯的代表自己,可以理解为正则表达式中的特殊代码,先说最常见的量词。
量词在正则中表示重复的意思,只修饰紧跟它之前的对象,可能是一个字符,可能是一个子组,这一点很重要,新手经常会搞错。
| 元字符 | 含义 |
|---|---|
| * | 0—>n次重复指定特征;量词都是”贪婪”的,它们会在不导致匹配失败的前提下,尽可能多的匹配字符,直到最大允许的匹配次数。 |
| + | 1->n次重复指定特征; |
| 它还有另外的用法:在量词后面紧跟一个+是”占有”性。它会吃掉尽可能多的字符, 并且不关注后面的其他特征,可以使用占有符 (+) 修饰量词来达到提升速度的目的。它的效果和一次性子组很像(?>)这个下一节讲 |
比如 .*abc 匹配 ”aabc”, 但是 .*+abc 不会匹配,
因为 .*+ 会吃掉整个字符串,从而导致后面剩余的模式得不到匹配。
| 元字符 | 含义 |
|---|---|
| { } | 表示自定义量词, 如{5,10}, 两个数值都必须小于 65536,且第一个数字不能为空,并且第一个数字必须小于等于第二个,如果第二个数字被省略,但是逗号仍然存在,就代表没有上限{5,}; 如果第二个数字和逗号都被省略,那么这个量词就限定的是一个确定次数的匹配{5}; |
[aeiou]{3,} 匹配至少三个连续的元音字母
| 元字符 | 含义 |
|---|---|
| ? | 量词,表示匹配其之前的字符 0 次或 1 次。 |
| 还可以放在量词后面用于改变量词的贪婪特性,它不再尽可能多的匹配,而是尽可能少的匹配字符,将匹配次数降到最小 |
PHP官方文档里有这么个例子,写的挺好:
/\*.*\*/ //用这个表达式来匹以下字符串,/*任意字符0个或多个*/
/* first comment*/ not comment /*second comment*/
默认情况下会匹配全文
而如果将表达式改为/\*.*?\*/,则只会匹配/* first comment*/
这里我把上一节的坑填一下,我在上一篇提到广义上的贪婪,看下面2个例子:
-
用表达式
'a*?3',去匹配’a3‘,按理说它应该只会匹配一个数字3,但其实它同样会匹配a3; -
再看一个:
'\d+?a',去匹配'133456789654a',为了能尽量满足匹配,即使使用了懒惰模式,依然会匹配整个字符;
这就是广义上的贪婪,对整个表达式而言的最大字符匹配,这个永远生效。
另外,我们还可以通过一个不匹配任何字符的子模式后面紧跟一个*来构造一个没有上限的无限循环。比如:(a?)*,这是个补充的小tip。
元字符-特殊类Meta-characters
这一类元字符常用的有以下几个:
| 元字符 | 含义 |
|---|---|
| [ ] | 字符类集合,注意:这里面包含的字符是一个集合,没有顺序。在目标字符串中匹配一个单独的字符,并非一串字符特征,这个要注意,比如[.?!]匹配的是单独一个标点符号; |
先介绍它,是因为同样一个元字符和在字符类[]内外有不同含义,大部分元字符
在字符类[]内部都失去了它们的特殊含义,但以下3个除外:
[^pattern] 非的关系,必须用在句首,把[]之后的内容取反,表明把[]内的所有字符类取反
比如[^()]表示所有非()的字符;[^aeiou]匹配所有非元音字母的字符。
[-] 标记字符范围,比如[W-c]等价于[wxyzabc]在大小写不敏感情况下;
[\] 转义,这个和[]外一样,同时一些转义字符也可以应用在[]内,
比如\d,\D \w,\W
接下来看字符类[]外的特殊元字符:
| 元字符 | 含义 |
|---|---|
| \ | 反斜线,一般用于转义,下一节具体讲。 |
| 句首,作为匹配位置锚点使用,(或在多行模式下是行首) | |
| $ | 句尾,作为匹配位置锚点使用,(或在多行模式下是行尾) |
| . | 句号,匹配除换行符外的任何字符(默认) |
| | | 或的关系,竖线左右两端是2个并列的可选特征,可选分支。 |
可选分支注意以下3点:
允许匹配空字符串的可选路径;
匹配的处理从左到右尝试每一个可选路径,使用第一个成功匹配的,
所以使用时要注意分支的顺序;
符号前面的所有内容(并非紧跟的)和后面的内容,为2个分支,
如果在子组里使用(|),则|前面的所有子组内容与|后面的构成2个分支;
转义
介绍完最基本的元素元字符之后,那么问题来了。如果我就像匹配一个星号*,不想让它表示量词,想让他恢复本来的意思,该怎么做?
这里就用到了正则中最常出现的字符,反斜线\转义字符了。了解它的含义,对我们读写正则非常关键。
| 字符 | 含义 |
|---|---|
| \ | 恢复紧接着的非字母或非数字的原本含义。比如\*,就表示*号,不表示量词。取消该字符所代表的特殊涵义。在中括号[ ]内部和外部都可用。因此要匹配一个反斜线 \,正则表达式写法是 \ \ |
反斜线除了能恢复元字符本身的含义,还可以用来描述特定字符。
下面每一对转义序列都代表了完整字符集中两个不相交的部分,任意字符不可能同时匹配两个,且所有小写都是代表yes,而大写都是代表no,成对儿出现:
| 字符 | 含义 |
|---|---|
| \d | digit十进制数字 |
| \D | 非十进制数字, |
| \s | space空白字符,小s |
| \S | 非空白字符,大S |
| \w | Word单词字符,注意:这里单词字符指的是任意字母、数字、下划线。 |
| \W | 非单词字符,经常使用[^\W\d_]来表示仅匹配字母 |
| \b | boundary单词边界,比如表达式’\bweb\b‘标记一个单词边界,所以只有独立的单词"web"会被匹配,而"webbing" 或 "cobweb"都不会匹配 |
| \B | 非单词边界,注意,如果目标字符串有几个单词和空格组成时,单词边!=字符串边界 |
举个例子:"tom is a cat", 可以用表达式^(\w+|\s)*$去匹配整个字符串,但如果使用\b.*\b只能匹配出tom
以上这些字符类序列在中括号[ ]内部或外部都可以出现。他们每次匹配所代表的字符类型中的一个字符。
下面介绍经常会用的几个特殊的转义字符:
| 字符 | 含义 |
|---|---|
| \A | 目标的开始位置 |
| \Z | 目标的结束位置或结束处的换行符 |
| \z | 目标的结束位置 |
| 特别说明 | \A, \Z, \z断言不同于^和$, 因为他们永远可以在任何模式下用于匹配目标字符串的开始和结束位置,而不会受特征修饰符的限制。而且这几个标记不能出现在字符类[ ]中,不会有任何作用 |
针对字符串中的隐藏格式符,正则也有相对的匹配,但这些字符在字符类[]中,没有特殊意义,只会当作普通字符对待:
| 制表符 | 含义 |
|---|---|
| \n | 换行符 |
| \r | 回车符 |
| \R | 换行符:能匹配 \n、\r、\r\n;'/^\R$/'可以匹配任意换行符 |
| \t | 水平制表符 tab |
| [\b] | 回退符,避免和\b冲突 |
特征修饰符Pattern Modifier
在第一节正则基本规则里,我们提到正则默认是大小写敏感,默认匹配单行字符串,量词匹配默认是贪婪的,那么如果你想大小写不敏感,匹配多行,或改变其贪婪属性,该怎么办呢?
这里就用到了特征修饰符。在正则里有一类字符比较特殊,它是用来修改整个匹配规则的,介绍几个比较常用的特征修饰符:
| 修饰符 | 对应模式 | 含义 |
|---|---|---|
| i | PCRE_CASELESS | 大小写不敏感 默认是敏感 |
| m | PCRE_MULTILINE | 匹配多行字符串模式 默认是单行。当这个修饰符设置之后,“行首”和“行末”就会匹配目标字符串中任意换行符之前或之后,另外还分别匹配目标字符串的最开始和最末尾位置。 |
| s | PCRE_DOTALL | 让元字符.可以匹配包含换行符在内的所有字符 |
| x | PCRE_EXTENDED | 表达式中没有经过转义的或不在字符类[ ]中的空白数据字符总会被忽略 可以帮我们规避误操作带来的问题 |
| U | PCRE_UNGREEDY | 取消贪婪模式,这种情况下,所有量词默认情况下就是非贪婪的了。但是,单个的量词可以通过紧跟一个 ? 来使其成为贪婪的。换句话说, /U这个选项逆转了贪婪的默认行为。 |
特征修饰符的使用效果有3种:
| 场景 | 方法 | 效果 |
|---|---|---|
| 主表达式 | 结束分隔符后面紧跟模式修饰符 | 影响整个表达式的匹配效果 |
| 主表达式 | (?紧跟修饰符) | 影响主表达式剩余部分的特征 |
| 子组 | (?紧跟修饰符) | 影响子组中剩余部分的特征 |
举例说明:
第一种:'/CAT[AEiou]/i',分隔符/后面的i将整个表达式不再区分大小写
第二种:’/CAT(?i)[AEiou]/',将(?i)直接放到主表达式,影响的是之后的[AEiou]不再区分大小写
第三种:'/(a(?i)Bc|d)/'可以匹配aBC,abC,abD等,这种影响也会穿透到可选分支
特征修饰符可以多个并列使用,比如(?im) 设置表明多行模式且大小写不敏感。同样可以用它来取消这些设置, 比如 (?im-sx) 设置了同时取消了PCRE_DOTALL 和 PCRE_EXTENDED模式。
好的,总结一下,这节我们了解了正则中的几个基本元素:元字符-量词,以及其贪婪特性;元字符特殊类,尤其是在字符类[ ]括号内外的区别;以及转义字符的作用,以及一些特殊的转义字符。最后,如何通过特征修饰符来修改正则默认的属性。
总结不易,请勿私自转载,否则死磕到底。
参考资料: www.php.net 官方文档