参考文献

  • 精通正则表达式第三版 Jeffrey E.F Friedl著
  • 学习正则表达式 [美]Micbael Fitzgerald

校验网址

元字符

元字符 特殊含义
. 匹配除换行符以外的任意字符
^ 匹配字符串的开始位置
$ 匹配字符串的结束位置
* 匹配前面的元素零次或多次
+ 匹配前面的元素一次或多次
? 匹配前面的元素零次或一次
\ 转义字符,用于转义特殊字符
[] 字符类,匹配方括号内的任意字符
() 分组,用于捕获或分组匹配
{} 限定符,指定匹配的次数
` `
\d 数字字符,等同于[0-9]
\w 单词字符,等同于[a-zA-Z0-9_]
\s 空白字符,包括空格、制表符、换行符等
\b 单词边界,匹配单词的开始或结束位置

量词

量词 说明
{n} 在它之前的元素必须出现n次
{m,n} 在它之前的元素最少出现m次,最多出现n次
{m,} 在它之前的元素最少出现m次,出现次数无上限
{0,n} 在它之前的元素,可以不出现,最多出现n次(在某些语言中可以写为{,n})

常用量词

常用量词 {m,n}等价形式 说明
* {0,} 可能出现,也可能不出现,出现次数没有上限
+ {1,} 至少出现1次.出现次数没有上限
? {0,1} 至多出现1次,也可能不出现

匹配优先量词与忽略优先量词

匹配优先量词 忽略优先量词 限定次数
* *? 可能出现,也可能不出现,出现次数没有上限
+ +? 至少出现1次.出现次数没有上限
? ?? 至多出现1次,也可能不出现
{m,n} {m,n}? 在它之前的元素最少出现m次,最多出现n次
{m,} {m,}? 在它之前的元素最少出现m次,出现次数无上限
{,n} {,n} 在它之前的元素,可以不出现,最多出现n次(

字符组[...]

匹配若干字符之一

1
2
3
RE: gr[ae]y
gray
grey
  • 在字符组内部,字符组元字符-(连字符)表示一个范围

    1
    [0-9a-zA-Z_!@#$%^&*()]
  • 只有在字符组内部,连字符才是元字符,否则它就是匹配普通的连字符号

排除型字符组[^...]

  • 这个字符组就会匹配任何未列出的字符,不是"不要匹配列出的字符"
  • 在字符组外部,^表示一个行描点,但是在字符组内部(而且不行是紧接在字符组的第一个方括号之后),它就是一个元字符.

分组(...)

  • 如果把一个表达式用括号包围起来,这个元素就是括号里的表达式,括号内的表达式通常被称为"子表达式"(sub-expression)
  • 括号的这种功能叫作分组(grouping).如果量词限定出现次数的元素不是字符或者字符组,而是连续的几个字符甚至是子表达式,就应该用括号将它们"编为一组".
  • 有了分组就可以准确表示"长度只能是m或n".

多选结构

  • 多选结构的一般表示法是(option1|option2)其中option1option2是两个作为多选分值的正则表达式.在多选结构中一般会同时使用括号()和竖线|;但是如果没有括号,只出现竖线|,仍然为多选结构.
    • 在多选结构中,竖线|用来来分隔多选结构,而括号用来规定整个多选结构的范围,如果没有出现括号,则将整个表达式视为一个多选结构,所以ab|cd等价与(ab|cd).
  • 多选分支不等于字符组.多选分支看起来类似字符组,如[abc]能匹配的字符串和(a|b|c)一样,[0-9]能匹配的字符串和(0|1|2|3|4|5|6|7|8|9)一样.从理论上说,可能完全用多选结构来替换字符组,但这种做法不推荐,理由在于:首先,[abc](a|b|c)要简洁许多,在多选结构中的每个分支都必须明确写出,不能使用-范围表示法.
  • 多选分支和字符组的另一个重要区别:排除性字符组可以表示"无法由某几个字符匹配的字符",多选结构却没有对应的结构表示"无法由某几个表达式匹配的字符串".
  • 注意: 如果出现多选结构应当尽量避免多选分支中存在重复匹配,因为这样会大大增加回溯的计算量.也就是说,应当避免这样的情况: 针对多选结构(option1|option2),某段文本既可以由option1匹配,也可以由option2匹配.如果出现了这样的多选结构,效率可能收到极大的影响.

引用分组

  • 括号不仅能把有联系的元素聚拢起来并分组,还有其他的作用–使用括号之后,正则表达式会保存每个分组真正匹配的文本,等匹配完成之后,通过group(num)之类的方法"引用"分组在匹配时捕获的内容.

    • 其中num表示对应括号的编号,括号分组的编号规则是从左向右计数,从1开始.因为捕获了文本,所以这种功能叫作捕获分组(captureing group).对应的,这种括号叫作捕获型括号
    • 也有编号为0的分组,它是默认存在的,对应整个表达式匹配的文本
    1
    2
    3
    4
    5
    6
    字符串: 2010  -  12  -  22
    字符串: 2010 - 12 - 22

    表达式: (\d{4]})-(\d{2]})-(\d{2]})

    分组编号: 1 2 3
  • 一般来说,正则表达式匹配完成之后,会得到一个表示"匹配结果"的对象,对它调用获取分组的方法,传入分组编号num,就可以获得对应分组匹配的文本.

反向引用(back-reference)

  • 它允许在正则表达式内部引用之前的捕获分组匹配的文本(也就是左侧),其形式也是\num,其中num表示所引用分组的编号.
  • 根据反向引用,查找连续重叠字母的表达式就是([[a-z]]\1),其中的[a-z]匹配的第一个字母,再用括号将匹配分组,然后用\1来反向引用.
  • 反向引用重复的对应捕获分组匹配的文本,而不是之前的表达式,即反向引用是一种"引用",对应的是由之前表达式决定的具体文本,它本身并不规定文本的特征.

非捕获分组(no-capturing-group)

  • 非捕获分组类似普通的捕获分组,只是在开括号后紧跟一个问号和冒号(?:...),这样的括号叫作非捕获型括号,它只能限定量词的作用范围,不捕获任何文本.
  • 分组的编号同样会按开括号出现的顺序从左到右递增,只是必须以捕获分组为准,会略过非捕获分组.

断言(assertion)

  • 正则表达式中大多数据结构匹配的文本会出现在最终的匹配结果中(一般用group(0)可以得到),但是也有些结构并不真正匹配文本,而只负责判断某个位置左/右侧的文本是否符合要求,这种结构被称为断言.
  • 常见的断言有三类:
    • 单词边界
    • 行起始/结束位置
    • 环视

单词边界

  • 使用\b表示单词边界
字符串 \brow\b \brow row\b
tomorrow
brown
row
rowdy
表达式说明 只能是单词row \b的右侧是单词字符,所以左侧不能是个单词字符 \b的左侧是单词字符,所以右侧不能是个单词字符
  • 单词边界不区分左右
  • 单词字符要求"另一边不是单词字符",而不是"另一边的字符不是单词字符",即一边必须是单词字符,另一边可以出现非单词字符,也可能没有任何字符.

行起始/结束位置

  • 单词边界匹配的是某个位置而不是文本,在正则表达式中,这类匹配位置的元素叫作锚点(anchor),它用来定位到某个位置.
  • 常用的锚点除了\b,还有^$分别表示匹配字符串的开始位置和结束位置
  • 多行模式最简单的办法是在正则表达式之前加上(?m)

环视

名字 记法 判断方向 结构内表达式匹配成功的返回值
肯定顺序环视 (?=...) 向右 True
否定顺序环视 (?!...) 向右 False
肯定逆序环视 (?<=...) 向左 True
否定逆序环视 (?<!...) 向左 False
  • 否定的意思是: “如果正则表达式匹配成功,则在当前位置匹配失败”

  • 顺序和逆序则表示正则表达式需要匹配的文本所在位置.

  • 记忆方式: 在当前位置,如果是朝右判断,则是顺序环视(lookhead),如果是朝左判断,则是逆序环视(lookbehind);如果要求子表达式能匹配的字符串必须出现,则肯定环视(positive),如果要求子表达式能匹配的字符串不能出现,则为否定环视(negative).

  • 示例,对于字符串12345,以\d{3}为表示式的四种环视能匹配的位置分别是:

    • 右侧必须出现三个数字字符
    • 右侧不能出现三个数字字符
    • 左侧必须出现三个数字字符
    • 左侧不能出现三个数字字符
    1
    2
    3
    4
    5
    									1		2		3		4		5
    (?=\d{3}) ↑ ↑ ↑
    (?!\d{3}) ↑ ↑ ↑
    (?<=\d{3}) ↑ ↑ ↑
    (?<!\d{3}) ↑ ↑ ↑
  • 环视的最大特点是:“匹配完成之后还停在原地”

匹配模式(match mode)

  • 匹配模式指的是匹配时遵循的规则.
  • 常用的匹配模式一共有四种:
    • 不区分大小写模式
    • 单行模式
    • 多行模式
    • 注解模式

不区分大小写模式

  • 模式的指定方式,通常有两种办法指定匹配的模式:
    • 以模式修饰符指定
      • 模式修饰符即模式名称对应的单个字符,使用时将其填入特定结构(?modifier)中(其中的modifier为模式修饰符),嵌在正则表达式的开头.比如不区分大小写的匹配模式的对应模式修饰符为i,对the指定此模式,完整的正则表达式就是(?i)the
      • 这种表达式几乎可以原封不动地在任何语言中使用,其意义都是相同的.
    • 以预定义的常量作为特殊参数传入来指定
  • 不区分大小写的匹配模式的对应模式修饰符为i(case Insensitive),表达式为(?i)

单行模式

  • 元字符点号.几乎能匹配任何字符,唯有换行符\n是例外的.
  • 单行模式对应的模式修饰符是s(Single line),表达式为(?s)

多行模式

  • 多行模式对应的模式修饰符是m(Multiline),表达式为(?m)

注释模式

  • (?#comment)

    1
    ^(?#start of the line)\d(?#digit).*(?#rest of the line)

转义

元字符的转义

结构 记法 转义 说明
字符组 [] \[] 只对开括号转义
字符组 . \.
字符组 - \- [a\-b]等价与[-ab]
量词 * + ? \* \+ \?
量词 *? +? ?? \*\? \+\? \?\?
量词 {m,n} \{m,n} 只对开花括号转义
括号 (...) \(...\) 开闭括号都要转义
多选结构 ` ` |
括号和多选结构 `(… …)` \(...|...\)
断言 ^ $ \^ \$
替换引用 $num \$$$ 在替换的replacement字符串中转义

常用示例

身份证

1
^[1-9]\d{14}(\d{2}[0-9x])?$