常用元字符
符号 | 说明 | 对应英语单词助记 |
---|---|---|
. |
匹配除换行符意外的任意字符 | |
\w |
匹配字母、数字、下划线、汉字 | word |
\s |
匹配任意的空白符,如\n 、\r 、\t 等 |
space |
\d |
匹配数字 | digital |
\b |
匹配单词的开始或者结束 | |
^ |
匹配字符串的开始 | |
$ |
匹配字符串的结束 |
常用限定符
符号 | 说明 |
---|---|
* |
>=0 次 |
+ |
>=1 次 |
? |
0 or 1 次 |
{n} |
n 次 |
{n,} |
>=n 次 |
{n, m} |
n 到 m 次 |
懒惰限定符
符号 | 说明 |
---|---|
*? |
重复任意次,但尽可能少重复 |
+? |
重复 >=1 次,但尽可能少重复 |
?? |
重复 0 或 1 次,但尽可能少重复 |
{n,m}? |
重复 n 到 m 次,但尽可能少重复 |
{n,}? |
重复 n 次以上,但尽可能少重复 |
以字符串aabab
为例,在贪婪模式下,a.*b
的匹配结果是aabab
,而懒惰模式下a.*?b
的结果则是aab
和ab
常用反义词
符号 | 说明 |
---|---|
\W |
匹配任意非字母、数字、下划线、汉字的字符 |
\S |
匹配任意非空白字符的字符 |
\D |
匹配任意非数字的字符 |
\B |
匹配非单词开头或结尾的位置 |
[^aeiou] |
匹配除了 aeiou 这几个字母以外的任意字符 |
常用的模式修正符
符号 | 说明 |
---|---|
i |
忽略大小写的匹配 |
g |
全局匹配 |
m |
将字符串视作多行,包含换行符仍能匹配 |
s |
将字符串视为单行,换行符也作为普通字符处理 |
x |
忽略模式中的空白 |
A |
强制从目标字符串开头匹配 |
D |
如果使用$ 限制结尾字符,则不允许结尾有换行 |
U |
值匹配最近的一个字符串,不重复匹配 |
e |
匹配函数preg_replace() 使用,可以把匹配到的字符串当做正则表达式执行 |
其它
符号 | 说明 |
---|---|
| |
分支条件 |
[] |
罗列所有需要匹配的字符。需要注意的是,在字母、数字间的中划线表示范围,如[0-9] 、[a-z] 、[0-9A-Z] ,而且需要顺序的表示,如[z-a] 无法匹配字符串abced 中的任何字符;如果中划线右侧无对应的字母或数字,则仅仅表示匹配中划线;在[] 中的^ 表示不包含其中的所有字符,而非字符串的起始 |
() |
对条件进行分组 |
零宽断言
(?=exp)
也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式 exp。比如 \b\w+(?=ing\b),匹配 以 ing 结尾的单词的前面部分 (除了 ing 以外的部分),如查找 I’m singing while you’re dancing. 时,它会匹配 sing 和 danc。
(?<=exp)
也叫 零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式 exp。比如 (?<=\bre)\w+\b 会匹配 以 re 开头的单词的后半部分 (除了 re 以外的部分),例如在查找 reading a book 时,它匹配 ading。
负向零宽断言
零宽度负预测先行断言 (?!exp)
, 断言此位置的后面不能匹配表达式 exp。例如:\d{3}(?!\d)
匹配 三位数字,而且这三位数字的后面不能是数字; \b((?!abc)\w)+\b
匹配 不包含连续字符串 abc 的单词。
零宽度负回顾后发断言(?<!exp)
,用于断言此位置的前面不能匹配表达式 exp:(?<![a-z])\d{7}
匹配 前面不是小写字母的七位数字。
一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)
匹配 不包含属性的简单 HTML 标签内里的内容。 (?<=<(\w+)>)
指定了这样的 前缀:被尖括号括起来的单词 (比如可能是 <b>
),然后是.*
(任意的字符串), 最后是一个 后缀 (?=<\/\1>)
。注意后缀里的 \/
,它用到了前面提过的字符转义;\1 则是一个反向引用,引用的正是 捕获的第一组,前面的 (\w+)
匹配的内容,这样如果前缀实际上是 <b>
的话,后缀就是 </b>
了。整个表达式匹配的是 <b>
和 </b>
之间的内容 (再次提醒,不包括前缀和后缀本身)。
如何阅读正则表达式
一个复杂的正则表达式是由简单的形式一点点组合而成,因此解读时也需要肢解后逐步理解。首先查找|
判断拆分为多种情况,然后查找()
再次细分,最后再根据最近原则判断限定修饰符的修饰范围,依次拆解后就会拨云见日了。同时,也可以借助可视化工具来理解,如
小感
正则虽然灵活强大,但对人类不够友好,书写与阅读都比较麻烦,现在很多语言的库或者函数都覆盖了常见类型的验证,如 PHP 中的filter_var()
支持域名、邮箱、IP、MAC 地址、URL 等验证,我们应当优先考虑这种优雅可读性好的验证方式,仅在不得已或正则更加简洁清晰的场景下使用正则,切勿滥用!