正则表达式完全指南:从入门到精通
正则表达式完全指南:从入门到精通
The Complete Guide of Regular Expression: Beginner to Mastery
一、简介 | Introduction
1.1 什么是正则表达式
正则表达式(Regular Expression)是一种用于描述字符串匹配模式的工具。它由一系列特殊字符和普通字符组成,可以用来检索、替换、提取那些符合某个模式的文本。
1.2 发展历史
正则表达式的概念最早由美国数学家斯蒂芬·科尔·克莱尼(Stephen Cole Kleene)于 1951 年提出,用于描述正则语言(即正规语言,能够被有限自动机识别的字符串集合)。1968 年,肯尼斯·蓝·汤普森(Ken Thompson) 将其引入文本编辑器 QED 和 Unix 的 ed 编辑器中,此后逐渐发展出 POSIX 标准和 Perl 风格两大流派,并被几乎所有现代编程语言所支持。
1.3 为什么需要正则表达式
在没有正则表达式的情况下,验证邮箱合法性可能需要写几十行 if-else 代码;而使用正则表达式则十分简洁:
1 | |
正则表达式广泛应用于:表单验证、批量替换、数据爬取、语法高亮等大家所熟悉的功能。
二、原理 | Principle
2.1 有限状态自动机
正则表达式的原理是有限自动机(Finite Automaton,FA,即由五个主要要素组成的一个顺序系统)。一个正则表达式在匹配时,本质上是在状态机中不断转移状态的过程。
例如正则表达式 ab*c 可以理解为:
1 | |
当输入字符串沿状态转移路径最终到达"接受状态"时,匹配成功。
2.2 两种引擎
常用的正则表达式的实现引擎有两种,分别是DFA(Deterministic finite automation, 确定有限自动机)和NFA(Nondeterministic Finite Automaton, 非确定有限自动机)。
前者每个状态对每个输入只有唯一转移,效率高但功能受限;后者效率较低,但是支持回溯操作,功能更强,选择更多。
2.3 回溯机制
大多数现代语言使用回溯 NFA引擎。匹配时,引擎会尝试一条路径,若失败则回退到上一个选择点尝试其他路径。
例如用 a.*b 匹配 axxbxxb:
-
a匹配第一个字符 -
.*剩余所有字符均被接受 -
发现后面没有
b了,开始回溯 -
回退到最后一个
b,匹配成功
然而,很显然地,回溯可能导致性能问题,如经典的 (a+)+b 面对大量 a 时会产生灾难性回溯(Catastrophic Backtracking)。
三、语法 | Grammar
3.1 普通字符
| 字符 | 含义 |
|---|---|
. |
匹配任意字符(除换行) |
\d |
数字 |
\D |
非数字 |
\w |
匹配字母数字下划线 |
\s |
空白字符(空格、Tab、换行) |
\S |
非空白字符 |
\b |
单词边界 |
\B |
非单词边界 |
3.2 非打印字符
| 字符 | 含义 |
|---|---|
\f |
换页符 |
\n |
换行符 |
\r |
回车符 |
\t |
制表符 |
\v |
垂直制表符 |
3.3 特殊字符
| 字符 | 含义 | 注释 |
|---|---|---|
$ |
字符串结尾 | |
() |
标记子表达式 | |
* |
匹配前面的表达式零次或多次 | 贪婪 |
+ |
匹配前面的表达式一次或多次 | 贪婪 |
? |
匹配前面的表达式零次或一次 | |
^ |
字符串开始或在方括号里表示取反 | |
\ |
转义 | 例如想匹配".“时需要使用”\." |
3.3.1 贪婪与非贪婪
称一个符号是贪婪的,即它会尽可能多的匹配;称一个符号是非贪婪的,即它会尽可少多的匹配。在贪婪的符号后加上?即可将其转换为非贪婪。
1 | |
3.4 限定符
| 字符 | 含义 |
|---|---|
{n} |
匹配前面的表达式确定的 n 次 |
{n,} |
匹配前面的表达式至少 n 次 |
{n,m} |
匹配前面的表达式 n 到 m 次 |
3.4 分组
| 字符 | 含义 |
|---|---|
(abc) |
定义一个可以被捕获的组 |
(?:abc) |
定义一个不可以被捕获的组 |
(?<name>abc) |
定义并命名一个可以被捕获的组 |
\1 |
反向引用第 1 个捕获组 |
3.5 断言
| 字符 | 含义 |
|---|---|
(?=...) |
正向先行断言(后面是什么) |
(?!...) |
负向先行断言(后面不是什么) |
(?<=...) |
正向后行断言(前面是什么) |
(?<!...) |
负向后行断言(前面不是什么) |
3.6 常用修饰符
| 修饰符 | 含义 |
|---|---|
i |
忽略大小写 |
g |
全局匹配 |
m |
多行模式 |
四、应用 | Application
5.1 验证合法性
1 | |
5.2 查询/更改
-
驼峰转下划线:
([a-z])([A-Z])->$1_$2,再转小写 -
删除空行:查找
^\s*\n替换为空 -
…
5.3 OI中高效实现程序
例如对于P7911 [CSP-J 2021] 网络连接,有一步需要判断地址串是否合法,如果用判断写需要如下代码:
1 | |
但是如果使用正则表达式仅需要如下代码:
1 | |
5.4 寻找单词/短语
例如匹配网站Nutrimatic便使用了正则表达式的语法和部分拓展,使用它便可轻松匹配符合特定格式的单词/短语,按频率依次排列。
例如使用_t_t_t_即可轻松匹配到statute和其它结果。
六、总结 | Summary
正则表达式是一门投入小、回报大、还能装点小逼的技能,十分建议学习。
掌握正则表达式,绝对能让你的文本处理效率提升一个数量级,并能在各种地方发现它,运用它。
理解、阅读、思辨
参考资源:
-
MDN Web Docs - Regular Expressions
-
正则表达式 - 百度百科
-
cppreference - Regular expressions
-
正则表达式 - 菜鸟教程
-
博客园、知乎与CSDN的各种文章

