正则表达式校验工具:https://regex101.com/
基本字符
[]
:用于自定义范围集,可指定字符、字符区间、或固定范围集
表达式 | 描述 |
---|---|
[abc] | 任意范围字符集。匹配集合中所含的任意单个字符。 |
[^abc] | 排除范围字符集。匹配任何不在集合中的字符。 |
[a-z] | 字符范围。匹配指定范围内的任意单个字符。 |
. | 匹配除换行符以外的任何单个字符,包括本身。 |
\ | 转义字符。用于表示特殊字符,如:^ - [ ] $ / 等字符 |
\w | 匹配任何字母、数字、下划线中的任意单个字符(等价于[A-Za-z0-9_] )。 |
\W | \W 表示\w 之外的字符,等价于[^A-Za-z0-9_] )。 |
\d | 数字。匹配0-9任何数字。 |
\D | 非数字。匹配任何非数字字符。 |
\s | 空白。匹配任何空白字符,包括空格、制表符、换行。 |
\S | 非空白字符。匹配任何非空白字符。 |
多个字符集可以组合在一起,形成一个更大的字符集,如:[\d\s]
逻辑控制符
在正则表达式中也有逻辑计算符,例如正则 Hi
,表示第一个字符等于H并且第二个字符等于i,它们是默认的&&
计算。如果要表达或的关系,就在中间加一个|
,如H|i
表示等于H或等于i。
正则中的逻辑控制符只有以下三组:
逻辑符 | 描述 |
---|---|
` | ` 或 |
() 子表达示 | 用于独立计算括号中的内容,支持嵌套。如:`(张 |
{} 数量控制 | 对字符或字表达的数量范围进行限定。如:张.{1,3} 表示“张”后面只能跟1到3个任意字符。 |
注意:正则中不存在异或( ^
)逻辑
说明:|
在类Unix系统中使用问题
由于
|
在类Unix系统中是特殊字符,当你使用grep
或vim
进行正则搜索时,必须进行转义。在类Unix系统使用正则搜索正确姿势是:# grep 使用正则 grep '401\|403\|404\|500' nginx.access.log # 在vim 中输入/ 开始正则搜索,同样|需要转义 /401\|403\|404\|500
子表达式
子表达示支持嵌套,如:(www|mvn|test-(bj|sz|gz|sh)).coderead.cn
表示 test子域名又可继续拆分为test-bj、test-sz、test-sh、test-gz。
子表达示也可用于分组引用。
数量控制
量词:即正则表达式中用于范围控制的符号,如 * + ? {m}
数量控制作用于字符或子表达示,已限制其数量范围。\d{6}
表示必须是6位数字。请注意:一个{}
仅作用于其前面的单个字符如:hi{2}
表示hii,而不是hihi。
量词 * + ?
实际就是对使用 {}
进行数量控制的一个简写
表达式 | 描述 |
---|---|
? | 匹配前面的表达式0个或1个。即表示可选项。相当于{0,1} |
+ | 匹配前面的表达式至少1个。 |
* | 匹配前面的表达式0个或多个。 |
{m} | 匹配前面的表达式m个。 |
{m,} | 匹配前面的表达式最少m个。 |
{m,n} | 匹配前面的表达式最少m个,最多n个。 |
Q:如何限制文本的长度范围?
A:例如限制密码的长度为6~20位:^.{6,20}$
注意:?
用于量词后面可以表示最少化匹配的意思(懒惰匹配)
下面举例说明 ? 的使用场景,下文中包括几对<span></span>
标签?
<span>hello</span> <span>uncle</span>
按照一般的思维肯定是两对<span>标签,但是实际上有3对,因为对于整个文本来说还有一对 <span>hello...uncle</span>
。
如图所示,如果使用正则表达式 <span>.*<span>
匹配<span>标签,那么将会匹配到最大的<span>hello...uncle</span>
标签,而不是像预期的那样匹配到两个小的/标签。
这时候就可以在量词后面加 ?
,告诉正则表达式引擎按最少化匹配。
<span>.*?</span>
和 <span>.*</span>
的区别可以这样理解,两个正则都是以 <span>
开头,中间为任何内容,直到遇到</span>
。但.*
非常“勤奋”,就算遇到了一个</span>
,还会继续向后查看是否还有,后面又找到了一个,就以最后找到的为准。而.*?
就比较“懒惰”,遇到第一个</span>
就直接匹配为一对<span>标签,然后就去查找下一对 <span> 标签了。
分组、引用和替换
表达式 | 描述 |
---|---|
(expression) | 分组。匹配括号里的整个表达式。 |
(?:expression) | 非捕获分组。匹配括号里的整个字符串但不获取匹配结果,拿不到分组引用。 |
\num | 对前面所匹配分组的引用。比如(\d)\1 可以匹配两个相同的数字,(Code)(Sheep)\1\2 则可以匹配CodeSheepCodeSheep 。 |
$组号 | 替换。替换操作指将正则匹配到的内容,替换成指定字符串,该字符串可通过$组号 引用组进行拼装。通过$0 可以引用整个匹配的内容。($0 在 Python与Javascript中不支持,使用$& 代替) |
说明:
- [] 和 () 的一个需要注意的区别是 [] 只能匹配单个字符,而 () 可以匹配多个字符。
[abc] 匹配 a 和 b 和 c
(abc) 匹配 abc
分组
分组指将匹配的内容,使用( )
划分成多个组块,分好的组可用于提取、反向引用以及替换操作。
![image-20220624165354986](https://i-blog.csdnimg.cn/blog_migrate/3e849436ced9840ce4991b19f02e7f5a.png)
举例1:在 javascript 中使用分组
// javascript
"小丽生日是2011-11-23".match(/(\d{4})-(\d{2})-(\d{2})/);
// 得出结果如下:
['2011-11-23', '2011', '11', '23']
// 一对括号表示一个分组,从1开始计数
移除分组
()
即用于子表达示,同时也是一个分组。如果只想用作子表达示,而不想用于分组就可以使用(?: )
从分组列表中移除。比如(?:\d{4})-(\d{2})-(\d{2})
该表达示只存在两个组,月$1
和日$2
。
嵌套分组
在嵌套分组中组号是如何命名的呢?比如:生日((\d{4})-(\d{2})(\d{2}))
其组号的命名顺序是以开括号出现顺序为准。
![image-20220624180531110](https://i-blog.csdnimg.cn/blog_migrate/7b72473e9f72a4199c392ecc3869a41b.png)
分组+量词
同一个分组如果使用了量词,该分组会代表多个值,这时通过$组号
去提取值的时候会得到该组最后匹配的值。如 (\d)+
匹配12345,通过 $1
将得到 5
反向引用
反向引用:指在表达示中通过\组号
引用之前的分组,但是不能够引用之后的内容。
![image-20220624170936130](https://i-blog.csdnimg.cn/blog_migrate/58fb436bfcf1c4de027159e00aa506d9.png)
举例2:在正则中引用分组,匹配html中的所有标题内容
文本内容如下
<h1>一级标题</h1>
<h2>二级标题</h2>
如果不使用分组,可以按照如下方式匹配,但是这样非常繁琐。
<h1>.*?<\/h1>|<h2>.*?<\/h2>
通过反向引用可以简化正则表达式
<(h[1-2])>.*?<\/\1>
![image-20220624170936130](https://i-blog.csdnimg.cn/blog_migrate/58fb436bfcf1c4de027159e00aa506d9.png)
引用替换
引用替换:正则有着强大的替换能力,比如匹配文本中所有空行,然后替换为空(删除);或者匹配所有的注释,然后替换为空;或者匹配普通文本中的所有http链接,然后替换为<a>标签;或者将文本替换为 insert sql 语句。
举例3:将下文中所有日期替换成yyyy-MM-dd 格式
实现替换的步骤如下:
- 写出匹配日期的正则:
\d{4}[-.\/]\d{2}[-.\/]\d{2}
- 对日期年、月、日进行分组:
(\d{4})[-.\/](\d{2})[-.\/](\d{2})
- 在替换字符中引用分组:
$1-$2-$3
![image-20220624172529129](https://i-blog.csdnimg.cn/blog_migrate/3cf89a436972704f28d8966a5e9eabe7.png)
替换后的结果
![image-20220624172805480](https://i-blog.csdnimg.cn/blog_migrate/598252882f7f2beb09fcfd576c674b42.png)
大小写转化
在Idea、VS Code、Sublime、Notepad++等工具进行替换操作时,还可以使用下表中操作符进行大小写转换,但是在编程语言中是不支持的。
操作符 | 描述 |
---|---|
\u 单个转大写 | 转换下一个字符为大写 |
\U 全部转大写 | 转换\U 后所有字符转大写 |
\U…\E 区间转大写 | \U 与\E 区间的内容转大写 |
\l 单个转小写 | 转换一下个字符为小写 |
\L 全部转小写 | 转换\L 后所有字符转小写 |
\L…\E 区间转小写 | \L 与\U 区间的内容转小写 |
具体使用方法是:在替换字符串中加入转换操作符。
举例:把单词首字母转成大写
- 编写匹配正则:
\w+
- 首字母转大写并替换:
\u$0
![image-20220624174203536](https://i-blog.csdnimg.cn/blog_migrate/05fd61c0739df28e601c012022f7e408.png)
转换后的结果为:Hello World!
边界断言
边界断言:指一段表达示前后是否满足指定条件,该条件由一个子表达式组成,基于前后字符能否匹配来计算布尔值。因断言部分不会消耗匹配字符,固又称为零宽断言。
边界断言让正则有了条件判断的能力,功能更加强大。
特殊边界断言
表达式 | 描述 |
---|---|
^ | 匹配断言文本或行开头。 |
$ | 匹配断言文本或行结尾。 |
\b | 匹配断言单词的开头或结尾。比如Sheep\b 可以匹配CodeSheep 末尾的Sheep ,不能匹配CodeSheepCode 中的Sheep 。 |
\B | 匹配非单词边界或结尾。比如Code\B 可以匹配HelloCodeSheep 中的Code ,不能匹配HelloCode 中的Code 。 |
\A 文本开头 | 断言文本开头。JavaScript 不支持 |
\Z 文本结尾 | 断言文本结尾。JavaScript 不支持 |
说明:
^
和$
配合边界/m
使用表示每一行的开头和结尾,否则表示的是整个文本的开头和结尾。被m
修饰后,^
表示行的开头,等价于(?<=\n|\A)
,被m
修饰后,$
表示行的结尾,等价于(?=\n|\Z)
。\b
单词边界本质上还是一个边界断言,符合边界断言的特性。\b
断言单词的前后是一个\W
字符,或是一个其它边界(行边界,文本边界)\bhello\b 等价于 (?<=^|\W|\A)Hello(?=$|\W|\Z)
边界断言语法
表达式 | 描述 |
---|---|
(?=) | 前置断言,判定一段表达式前面是否满足条件。比如Code(?=Sheep) 能匹配CodeSheep 中的Code ,但不能匹配CodePig 中的Code 。 |
(?!) | 前置否定断言,判定一段表达式前面是否不满足条件。比如Code(?!Sheep) 不能匹配CodeSheep 中的Code ,但能匹配CodePig 中的Code 。 |
(?<=) | 后置断言,判定一段表达式后面是否满足条件。比如(?<=Code)Sheep 能匹配CodeSheep 中的Sheep ,但不能匹配ReadSheep 中的Sheep 。 |
(?<!) | 后置否定断言,判定一段表达示后面是否不满足条件。比如(?<!Code)Sheep 不能匹配CodeSheep 中的Sheep ,但能匹配ReadSheep 中的Sheep 。 |
说明:所谓前置后置是以表达式为中心,边界断言位于表达式的前面(左边)和后面(右边)
例如:
(?<=身高)\d{3}(?=cm)
中(?<=身高)
为后置断言(表达式后面),(?=cm)
为前置断言。
注意:后置断言在javascript中只有部分浏览器支持。另外后置断言非常消耗性能,所以不推荐使用无限大的量词如:*
+
{n,}
。甚至在JAVA、Python、PHP会直接报语法错误。
高级特性
- 零宽断言:断言条件本身不会消耗字符
- **多边界断言:**一个正则可同时存在多个边界断言。根据其所处位置来决定断言的边界。
- 条件组合:多个子断言可以进行布尔运算如:
&&
||
()
, - 任意边界:可以是任意合法的表达式边界,甚至可以是空字符边界。
高级特性之条件组合
边界条件本质上就是布尔值计算,其自然可以进行类似&&
||
()
布尔运算,以应对更复杂的场景。其书写方式有以几种:
h(?=条件1)(?=条件2)
且
运算,指必须同时满足多个条件h(?=(?=条件1)(?=条件2))
且
运算,条件1与条件2组成一个新条件,并且两个条件都必须满足h(?=(?=条件1)|(?!条件2))
或
运算,满足条件1或者 不满足 条件2h(?=表达式1|(?=条件1)(?!条件2))
混合
运算,表示满足表达式1或者同时满足条件1、2
上述条件组合在后置断言中同样适用,而且没有额外的兼容性问题。另外上述任意条件都是基于同一个边界进行计算,即字符h
修饰符
修饰符用于影响表达式的匹配逻辑。
表达式 | 描述 |
---|---|
/.../i | 忽略大小写。(… 表示正则表达式) |
/.../g | 全局匹配。默认只会匹配一个结果,加上 g 后会匹配全部可匹配结果 |
/.../m | 行边界修饰符。用于多行匹配。 |
/.../s | 使用此修饰符后 . 能匹配任意字符,包括换行符。 |
/.../x | 书写正则表达式时会忽略空白字符,可以多行书写,并可以使用#进行注释说明。JavaScript 不支持 |
对
/m
的理解:它的作用是于定义^
与$
边界断言的作用范围。默认情况下^$
分别表示文本的开头与结尾,加上之后表示行首与行尾,也包括文本开头与结尾。一般的正则表达式应用都会加上m
修饰符。
在使用类似idea,vs code,或notepad++等工具时,其正则都添加了gmi
三个修饰符,而且除了i
大小写勿略,其它都不可以改变。
常用正则表达式示例
详情参考