正则表达式语法
正则表达式(Regular Expression)是一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
1. 正则表达式规则:
1.1 普通字符
字母、数字、汉字、下划线、以及后边章节中没有特殊定义的标点符号,都是"普通字符"。表达式中的普通字符,在匹配一个字符串的时候,匹配与之相同的一个字符。
1.2 简单的转义字符
一些不便书写的字符,采用在前面加 "" 的方法。
字符 | 描述 |
---|---|
\\ |
匹配 \ 本身 |
\f |
匹配一个换页符。等价于 \x0c 和 \cL 。 |
\n |
匹配一个换行符。等价于 \x0a 和 \cJ 。 |
\r |
匹配一个回车符。等价于 \x0d 和 \cM 。 |
\t |
匹配一个制表符。等价于\x09 和 \cI 。 |
\v |
匹配一个垂直制表符。等价于 \x0b 和 \cK 。 |
还有其他一些在后边章节中有特殊用处的标点符号,在前面加 "" 后,就代表该符号本身。
字符 | 描述 |
---|---|
\^ |
匹配 ^ 符号本身。 |
\$ |
匹配 $ 符号本身。 |
\. |
匹配小数点(. )本身。 |
这些转义字符的匹配方法与 "普通字符" 是类似的。也是匹配与之相同的一个字符。
1.3 能够与 '多种字符' 匹配的表达式
以下表达式可以匹配 '多种字符' 中的任意一个字符,注意只能是一个,不是多个。
字符 | 描述 |
---|---|
\d |
匹配任意一个数字,0~9 中的任意一个。 |
\w |
匹配任意一个字母或数字或下划线,也就是 A ~ Z ,a ~ z , 0 ~ 9 , _ 中任意一个。 |
\s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v] 。注意 Unicode 正则表达式会匹配全角空格符。 |
\S |
匹配任何非空白字符。等价于 [^ \f\n\r\t\v] 。 |
. |
小数点可以匹配除了换行符(\n )以外的任意一个字符。 |
1.4 自定义能够匹配 '多种字符' 的表达式
使用方括号 [ ] 包含一系列字符,能够匹配其中任意一个字符。用 [^ ] 包含一系列字符,则能够匹配其中字符之外的任意一个字符。同样的道理,虽然可以匹配其中任意一个,但是只能是一个,不是多个。
字符 | 描述 |
---|---|
[ab5@] |
匹配 a 或 b 或 5 或 @ 。 |
[^abc] |
匹配 a ,b ,c 之外的任意一个字符。 |
[f-k] |
匹配 f~k 之间的任意一个字母。 |
[^A-F0-3] |
匹配 A~F ,0~3 之外的任意一个字符。 |
1.5 修饰匹配次数的特殊符号 — 限定符
前面章节中讲到的表达式,无论是只能匹配一种字符的表达式,还是可以匹配多种字符其中任意一个的表达式,都只能匹配一次。如果使用表达式再加上修饰匹配次数的特殊符号,那么不用重复书写表达式就可以重复匹配。限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 +
或 ?
或 {n}
或 {n,}
或 {n,m}
共6种。
字符 | 描述 |
---|---|
{n} | 表达式重复n次。n 是一个非负整数。例如,o{2} 不能匹配 Bob 中的 o ,但是能匹配 food 中的两个 o 。 |
{n,} | 表达式至少重复 n 次。n 是一个非负整数。例如,o{2,} 不能匹配 Bob 中的 o ,但能匹配 foooood 中的所有 o 。o{1,} 等价于 o+ 。o{0,} 则等价于 o* 。 |
{m,n} | 表达式至少重复 m 次,最多重复 n 次。m 和 n 均为非负整数,其中n >= m 。例如,o{1,3} 将匹配 fooooood 中的前三个 o 。o{0,1} 等价于 o? 。请注意在逗号和两个数之间不能有空格。 |
? | 匹配前面的子表达式 0 次或 1 次。例如,do(es)? 可以匹配 do 或 does 。又例,a[cd]? 可以匹配 a ,ac ,ad
|
+ | 匹配前面的子表达式 至少出现1次。例如,zo+ 能匹配 zo 以及 zoo ,但不能匹配 z
|
* | 匹配前面的子表达式不出现或出现任意次。例如,zo* 能匹配 z 以及 zoo ,* 等价于{0,}
|
1.6 其他一些代表抽象意义的特殊符号
一些符号在表达式中代表抽象的特殊意义:
字符 | 描述 |
---|---|
^ |
与字符串开始的地方匹配,不匹配任何字符。例如, ^aaa 能匹配aaa xxx xxx
|
$ |
与字符串结束的地方匹配,不匹配任何字符。例如, aaa$ 能匹配xxx xxx aaa
|
\b |
匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符。例如,表达式 \bend\b 在匹配 weekend,endfor,end 时,匹配结果是 end
|
一些符号可以影响表达式内部的子表达式之间的关系:
字符 | 描述 |
---|---|
| | 左右两边表达式之间 "或" 关系,匹配左边或者右边 |
( ) | (1). 在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰 (2). 取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到 |
2. 正则表达式中的一些高级规则
2.1 匹配次数中的贪婪和非贪婪
贪婪模式
在使用修饰匹配次数的特殊符号时,有几种表示方法可以使同一个表达式能够匹配不同的次数,比如:{m,n}
, {m,}
, ?
, *
, +
,具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中,总是尽可能多的匹配。这种匹配原则就叫作 "贪婪" 模式 。
例如:针对文本 dxxxdxxxd"
,正则表达式 (d)(\w+)(d)
会匹配尽可能多的字符,因此匹配整个文本。
匹配结果:

再例:针对字符串 <td><p>aa</p></td> <td><p>bb</p></td>
,正则表达式 <td>(.*)</td>
会匹配尽可能多的字符,匹配到的内容是 <td><p>aa</p></td> <td><p>bb</p></td>
整个字符串, 表达式中的 </td>"
将与字符串中最后一个 </td>
匹配。
匹配结果:

非贪婪模式
在修饰匹配次数的特殊符号后再加上一个 ?
号,则可以使匹配次数不定的表达式尽可能少的匹配,使可匹配可不匹配的表达式,尽可能的 "不匹配"。这种匹配原则叫作 "非贪婪" 模式,也叫作 "勉强" 模式。
例如:针对文本 dxxxdxxxd"
,正则表达式 (d)(\w+?)(d)
会匹配尽可能少的字符,因此匹配符合条件的前五个字符。
匹配结果:

再例:针对字符串 <td><p>aa</p></td> <td><p>bb</p></td>
,表达式 <td>(.*?)</td>
匹配尽可能少的匹配字符,将只得到 <td><p>aa</p></td>
, 再次匹配下一个时,可以得到第二个 <td><p>bb</p></td>
。
匹配结果:

2.2 反向引用 \1,\2 ...
表达式在匹配时,表达式引擎会将小括号 ( )
包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取。这一点,在前面的举例中,已经多次展示了。在实际应用场合中,当用某种边界来查找,而所要获取的内容又不包含边界时,必须使用小括号来指定所要的范围。比如前面的 <td>(.*?)</td>
。
其实,小括号包含的表达式所匹配到的字符串
不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。表达式后边的部分,可以引用前面 括号内的子匹配已经匹配到的字符串
。引用方法是 \
加上一个数字。\1
引用第1对括号内匹配到的字符串,\2
引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 (
在前,那这一对就先排序号。
例如,表达式 ('|")(.*?)(\1)
在匹配 'Hello', "World"
时匹配到的内容是:'Hello'
。再次匹配下一个时,可以匹配到 "World"
。

2.3 预搜索,不匹配;反向预搜索,不匹配
前面的章节中,我讲到了几个代表抽象意义的特殊符号:"^","$","\b"。它们都有一个共同点,那就是:它们本身不匹配任何字符,只是对 "字符串的两头" 或者 "字符之间的缝隙" 附加了一个条件。理解到这个概念以后,本节将继续介绍另外一种对 "两头" 或者 "缝隙" 附加条件的,更加灵活的表示方法。
正向预搜索
格式:"(?=xxxxx)"
在被匹配的字符串中,它对所处的 "缝隙" 或者 "两头" 附加的条件是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件,所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "\b",本身不匹配任何字符。"\b" 只是将所在缝隙之前、之后的字符取来进行了一下判断,不会影响后边的表达式来真正的匹配。
格式:"(?!xxxxx)"
所在缝隙的右侧,必须不能匹配 xxxxx 这部分表达式。
反向预搜索
格式:"(?<=xxxxx)"
所在缝隙的左侧,必须能够匹配指定表达式,而不是去判断右侧。
格式:"(?<!xxxxx)"
所在缝隙的左侧,必须不能够匹配指定表达式。与 "正向预搜索" 一样的是:它们都是对所在缝隙的一种附加条件,本身都不匹配任何字符。
与 "正向预搜索" 一样的是:它们都是对所在缝隙的一种附加条件,本身都不匹配任何字符。