RegExp 正则表达式

未来的编程能力会像今天的汽车驾驶能力和计算机使用能力一样普及。

常用元字符

符号 说明 对应英语单词助记
. 匹配换行符意外的任意字符
\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的结果则是aabab

常用反义词

符号 说明
\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 等验证,我们应当优先考虑这种优雅可读性好的验证方式,仅在不得已或正则更加简洁清晰的场景下使用正则,切勿滥用!

参考资料

  1. 正则表达式 30 分钟入门教程
  2. 在线正则表达式测试
因为热爱,所以执着。