这篇文章主要是介绍了正则表达式中分支、分组、反向引用、贪婪匹配与非贪婪匹配、环视等知识点。
分支
分支 就是在正则表达式可以有多种匹配情况,在正则表达式(一)提到过在元字符[]内的字符称之为字符组如[awq]
,还有另一种表达式写法就是分支(a|w|q)
,那么分支符号就是|
咯。
如果想匹配
cook
、look
,这里可以写成[cl]ook
,那么我想要匹配cook
、look
、caook
,这时候字符组并不能满足要求([]只能匹配单个字符),那么就用分支形式(ca|c|l)ook
。(分支可以是更复杂的表达式,而字符组的只能匹配单个字符,如果匹配单个字符的情况选择字符组,效率会高些)
我们在继续看复杂点的表达式,例如
0\d{2}-\d{8} | 0\d{3}-\d{7}
此表达式意思就是可匹配三位区号,8位本地号(010-12345678)或者四位区号,7位本地号的号码。
另外要注意的是分支的条件顺序(从左到右,一旦匹配成功则不再继续匹配),例如
\d{2}-\d{8}|\d{2}
、\d{2}|\d{2}-\d{8}
,第一个表达式可以匹配(23-12345678或者23),而第二个表达就只会匹配前两位(23),所以写分支时要注意条件顺序的位置。
分组
重复单个字符我们只需要在字符后面加上限定符,但如果想要重复多个字符该怎么办呢?
可以用小括号指定子表达式,重复子表达式的次数,也就是正则表达式中的分组
。
类别 | 语法 | 意义 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名组里 |
捕获 | (?<name> exp) |
匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) |
捕获 | (?:exp) | 匹配exp,不捕获文本,也不给此组分配组号 |
零宽断言 | (?=exp) | 匹配exp后面的位置 |
零宽断言 | (?<=exp) | 匹配exp前面的位置 |
零宽断言 | (?!exp) | 匹配后面跟的不是exp的位置 |
零宽断言 | (?<!exp) |
匹配前面跟的不是exp的位置 |
注释 | (?#comment) | 提供注释拥有阅读,并对表达式没有任何影响 |
反向引用(用于重复匹配子表达式内容文本)
(\d)\1{2}-(\d)\d\2-\1{3}
可匹配的结果是333-454-333
(此表达式匹配结果的形式就是xxx-yzy-xxx),第一个小括号(\d)
(捕获到的文本内容就分配给编号1的分组中),然后接是分组1捕获的内容(即\1
也就是第一个小括号的内容)重复两次,接着就是-
,再第二个小括号(\d)
(捕获到的文本内容就分配给编号2的分组中),接着匹配\d
,然后接是分组2捕获的内容(即\2
) ,接着就是-
,最后又重复三次分组1捕获的内容(即\1
);环视 即匹配的是位置,而不会匹配内容
顺序肯定环视
(?=exp)
\b\w+(?=ook\b)
,匹配以ook
结尾的单词前面的部分(就是除了
ook以外的部分
),i am look
那么此字符串匹配到look
中的l
字母。((?=ook\b)
就是匹配位置,而不会去匹配内容)逆序肯定环视
(?<=exp)
(?<=\bst)\w+\b
,匹配以st
开头的单词后面的部分(就是除了
st以外的部分
),staring abc
,那么此字符串匹配到staring
中的aring
。顺序否定环视
(?!exp)
在正则表达式(一)时候提到过反义,例如
\b\w*a[^t]\w*\b
,那么匹配中就是字母a后面不可以跟t字母,如ra
这种是以a字母结尾是匹配不了的,因为[^t]是要匹配一个字符的(空格或其他),\w*\b
可以匹配其他字符,那么就有ra string
这种匹配情况。
为了解决上面的情况,我们可以引用(?!exp)
,它只是匹配一个位置,不占有任何字符,所以表达式是\b\w*a(?!t)\w*\b
逆序否定环视
(?<!exp)
(?<![a-z])\d{3}
,前面不可以小写字母的3位数,如A123,则匹配到123。再举个例子,如整个匹配文本不能出现字符串”abc”,这个正则表达式应该是
^(?:(?!abc).)+$
注意,括号匹配会捕获文本,如需不捕获可以用环视以及(?:)
总体而言,环视相当于对”所在位置”附加一个条件,难点在于找到这个”位置”。
贪婪/懒惰匹配模式
当正则表达式中包含能接受重复的限定符时,通常的行为时(在使整个式能匹配的前提下)匹配尽可能多的字符,例如a.*b
,如果用来搜索aabab
,它会匹配整个字符串(即正则表达式中的贪婪匹配)
有时,我们需要匹配尽可能少的字符,即懒惰匹配,我们改变下前面表达式的限定符中加上?
(即懒惰匹配模式),那么表达式就是a.*?b
,同上用于搜索aabab
,最先匹配到aab
和ab
这两组字符
既然是懒惰匹配为啥会先匹配到aab
呢?简单地说表达式中有,比懒惰/贪婪匹配规则的优先级更高:最先开始的匹配是拥有最高优先权的
常用懒惰限定符如下表
懒惰限定符 | 意义 |
---|---|
*? | 重复0次或更多次,但尽可能的少重复 |
+? | 重复1次或更多次,但尽可能的少重复 |
?? | 重复0次或1次,但尽可能的少重复 |
{n,m}? | 重复n次到m次 ,但尽可能的少重复 |
{n,}? | 重复n次或更多次,但尽可能的少重复 |
1 | <?php |
运行上述的代码,结果是
1 | array(2) { |
由于上述正则表达式中限定符.*
会引发贪婪匹配模式,所以会一直匹配”<a herf='http://baidu.com'>
“后的内容,直至遇到结束条件”<\/a>”,所以以至于匹配出我们不想要的结果,可以把表达式限定符加个?
,/<a[^>]+>(.*?)<\/a>/
,那么运行的结果也就是我们想要的结果啦(还可以把上述的表达式修改为/<a[^>]+>([^<>]*)<\/a>/
也可以)