简介

正则表达式是用于描述字符串匹配模式的表达式。利用正则表达式进行匹配,可以实现检查字符串是否符合某种规则、字符串是否含有某种子串;替换匹配的子串或者从某个串中取出符合某个条件的子串。

正则表达式的引擎是一种自动机,在根据规则完成自动机的构建后,对任意字符串的匹配都将花费 O(n) 的时间复杂度。有关正则表达式的理论及实现本文并不继续深入。

基本语法

这里将介绍正则表达式的基本语法。另外这里推荐网站 regex101,可以用于验证正则表达式。

字符与字符集

正则表达式中一般的字符用于匹配字符串中对应的相同字符。例如正则表达式 “a” 可以匹配字符串中的字符 ‘a’ 。 “abc” 可以匹配字符串中的子串 “abc” 。

对于在正则表达式中具有特殊含义的字符,需要进行转义,在原字符前加上反斜杠 “\”

用方括号将一个或多个字符括起来表示一个字符集,一个字符集匹配在该字符集中出现的字符。例如 [abc],可以匹配 ‘a’ ‘b’ 或 ‘c’。

还可以在字符集中指定要匹配的字符的范围,例如 [a-z],用来匹配所有的小写英文字母。在同一字符集内可以有多个范围,例如 [a-zA-Z0-9]。

在字符集括号内的所有字符之前添加 “^” 表示对该字符集取反,即匹配所有不在字符集内的元素。例如 [^a-b] 匹配所有不是小写英文字母的元素。

字符 “.” 可用于匹配换行符为所有字符。

限定符

限定符用来指定其前面的部分将要匹配几次。例如a{2,5}匹配2到5个a,即"aa"、“aaa”、“aaaa"和"aaaaa”。具体的限定符含义如下表所示:

限定符解释
{n}匹配内容n次
{n,}匹配内容次数大于等于n次
{n,m}匹配内容次数为n到m次
*匹配零次或多次,同{0,}
+匹配一次或多次,同{1,}
?匹配零次或一次,同{0,1}

注意,限定符匹配默认遵循贪婪原则,即在同样能够完成匹配的情况下,会匹配尽可能多的字符。例如要匹配<html><dir>hello,world</dir></html>中的标签,若使用正则表达式 “<.+>",则只会匹配整个字符串。 解决方法是在限定符后加上一个问号 “?” 。这样限定符的匹配模式便会切换为懒惰匹配,即在同样能够完成匹配的情况下,会匹配尽可能少的字符。

用括号将一部分表达式括起,可以将这部分表达式作为一个整体。

比如说,需要匹配 “aacacaaac”,可以归纳出字符串中重复的部分 “a+c”,将该部分作为一个整体,则该部分重复了三次。最终得到可以匹配该字符串的正则表达式为 “(a+c){3}"。

另外,组分为捕获组与非捕获组,捕获组即单纯的括号,非捕获组包括 “(?:exp)” “(?=exp)” “(?!exp)” “(?<=exp)” “(?<!exp)"。这里先说明 “(exp)” 和 “(?:exp)” 的区别。”(?=exp)” “(?!exp)” “(?<=exp)” “(?<!exp)” 会在后一节进一步解释。

当使用捕获组时,表示对括号内会出现的内容更感兴趣。这时在匹配成功后缓存括号内的匹配内容,并可以访问该内容。而使用非捕获组,则说明仅仅将括号用于划分表达式,因此不会缓存括号内的匹配。

选择

将不同的内容用 “|” 分割,用来表示进行该部分匹配时不同的匹配选项。例如 “learn(ed|t)” 可以匹配 “learnt” 和 “learned”。

正如前一节所说,这里使用了捕获;不使用捕获的表达式为 “learn(?:ed|t)”

“(?=exp)” “(?!exp)” “(?<=exp)” “(?<!exp)” 也可以实现匹配选择的功能。

exp1(?=exp2)会匹配 exp2 前面的 exp1。例如表达式 “wok(?=[0-9]+)” 只会匹配后面带数字的 “wok”, 例如 “wok123” 中的 “wok” , 而不会匹配 “wokron”、 “wokd234” 中的 “wok” 。

“wok(?=[0-9]+)([0-9]+)” 可以捕获 “wok” 后的数字大小。

exp1(?!exp2)会匹配后面不是 exp2 的 exp1。例如表达式"wok(?![0-9]+)” 只会匹配后面不带有数字的 “wok”。

“^(?:000[1-9]|(?!000)\d{4})$“会匹配0001-9999的所有值。

(?<=exp1)exp2会匹配前缀为 exp1 的 exp2。例如表达式”(?<=foo)bar"会匹配前缀为foo的bar。

(?<!epx1)exp2会匹配前缀不为 exp1 的 exp2。例如表达式”(?<!foo)bar"会匹配所有前缀不为foo的bar。

“^(?:000[1-9]|\d{3}(?<!000)\d)$“同样可以匹配0001-9999的所有值。

定位符

定位符可以将正则表达式的匹配对象定位到行首或行尾。又或者单词的开头结尾。下表是一些定位符:

定位符描述
^匹配输入字符串开始的位置
$匹配输入字符串结尾的位置
\b匹配一个单词边界,即字与空格间的位置
\B非单词边界匹配

常用元字符

这里总结了一些常用的元字符,见表格:

字符描述
\将下一个字符标记为特殊字符、或转义符
^匹配输入字符串的开始位置
$匹配输入字符串的结束位
*匹配前面的子表达式零次或多次
+匹配前面的子表达式一次或多次
?匹配前面的子表达式零次或一次
{n}匹配确定的 n 次
{n,}至少匹配n 次
{n,m}最少匹配 n 次且最多匹配 m 次
?跟在其他限制符后面,设置匹配模式为非贪婪
.匹配除换行符(\n、\r)之外的任何单个字符
x|y匹配 x 或 y
[xyz]字符集合。匹配所包含的任意一个字符
[^xyz]负值字符集合。匹配未包含的任意字符
[a-z]字符范围。匹配指定范围内的任意字符
[^a-z]负值字符范围。匹配任何不在指定范围内的任意字符
\b匹配一个单词边界,即单词和空格间的位置
\B匹配非单词边界
\d匹配一个数字字符。等价于 [0-9]
\D匹配一个非数字字符。等价于 [^0-9]
\f匹配一个换页符。等价于 \x0c 和 \cL
\n匹配一个换行符。等价于 \x0a 和 \cJ
\r匹配一个回车符。等价于 \x0d 和 \cM
\s匹配任何空白字符
\S匹配任何非空白字符
\t匹配一个制表符。等价于 \x09 和 \cI
\v匹配一个垂直制表符。等价于 \x0b 和 \cK
\w匹配字母、数字、下划线。等价于’[A-Za-z0-9_]’
\W匹配非字母、数字、下划线。等价于 ‘[^A-Za-z0-9_]’
\num匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,’(.)\1’ 匹配两个连续的相同字符