简介
正则表达式是用于描述字符串匹配模式的表达式。利用正则表达式进行匹配,可以实现检查字符串是否符合某种规则、字符串是否含有某种子串;替换匹配的子串或者从某个串中取出符合某个条件的子串。
正则表达式的引擎是一种自动机,在根据规则完成自动机的构建后,对任意字符串的匹配都将花费 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’ 匹配两个连续的相同字符 |