正则表达式语法
[TOC]
元字符
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
字符转义
如果想查找元字符本身的话,就需要将字符转义 如:\* \.
重复
代码 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
字符类
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?
- [aeiou] 匹配元音字母
- [0-9] 匹配数字范围0-9(与\d含义一致)
- [a-z0-9A-Z_] 匹配字母数字下划线(只考虑英文时,与\w含义一致)
案例1:
匹配几种电话号码:
(010)88886666,或022-22334455,或02912345678
\(?0\d{2}[) -]?\d{8}
分枝条件
分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。
观察案例1
表达式,发现其匹配存有以下缺陷:
能够同时匹配010)12345678或(022-87654321这种不正确的格式.因此,解决这种问题要使用分枝条件,如下:
- 0\d{2}-\d{8}|0\d{3}-\d{7}
这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)
- \(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}
这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。
- \d{5}-\d{4}|\d{5}
这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。
注意: 用分枝条件时,要注意各个条件的顺序,上面例子如果改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
分组
当想要重复多个字符时,可以使用小括号来指定子表达式(也叫做,分组),然后可以指定子表达式的重复次数.
案例2
匹配ip地址:
- (\d{1,3}\.){3}\d{1,3}
简单的ip地址匹配,缺陷是会匹配到256.300.888.999这种不可能存在的IP地址
- ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
精确匹配ip地址,由于正则不支持算术比较,所以只能使用冗长的分组和分枝条件
反义
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义
代码 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本.
案例3
匹配重复的单词
- \b(\w+)\b\s+\1\b 匹配go go或kitty kitty这类单词(\1代表第一个分组)
组名也可以自定义,语法如下:
(?<name>exp)
案例3变形如下:
- \b(?<Word>\w+)\b\s+\k<Word>\b
注意:\k<name>表示使用定义的别名
后向引用其它用法总结:
分类 | 代码/语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) | |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号(一般用于只验证规则,不需要捕获内容) | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<=exp)< td> | 匹配exp后面的位置 | =exp)<>|
负向零宽断言 | (?!exp) | 匹配后面跟的不是exp的位置 |
(?<!exp) | 匹配前面不是exp的位置 | |
注释 | (?#comment) | 此类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
going
\w+(?=ing) 零宽断言
go
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符.如:
a.b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配*。
相反,有时需要尽可能少的匹配,称为懒惰匹配,语法是在表达式之后加一个?.同上面表达式变成懒惰匹配 : a.*?b
代码/语法 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
修饰符(标记)
正则表达式的标记用于指定额外的匹配策略。标记不写在正则表达式里,标记位于表达式之外。
格式:/pattern/flags
修饰符 | 说明 |
---|---|
i | (ignore)忽略大小写。 |
g | 全局匹配。默认正则过程中字符串从左到右匹配,找到第一个符合条件的即匹配成功。使用该修饰符,查找所有匹配项。 |
m | 多行模式,边界字符 `^` 和 `$` 匹配每一行的开头和结尾,而不是整个字符串的开头和结尾。 |
s | `“.”`表达式包含换行符`“\n”`。默认情况下的`"."` 是 匹配除换行符 `"\n"` 之外的任何字符,加上 `s` 修饰符之后包含换行符 `"\n"`。 |
u | 完整的 unicode 支持。默认正则不支持四个字节的 UTF-16 编码,会将其识别为两个字符。该修饰符将会正确识别为一个字符,建议汉字匹配都加上该修饰符。 |
y | (sticky)“粘连”修饰符,与`g`类似也是全局匹配,不同之处在于,`g`修饰符只要剩余位置中存在匹配就可,而`y`修饰符确保匹配必须从剩余的第一个位置开始。有些实现需要与`g`一起使用才可全局匹配。 |
# u 修饰符
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
# y 修饰符
字符串:a_a_a_a_aa_a_a_
正则:/a_/gy
匹配结果:a_a_a_a_