什么是正则表达式?
正则表达式(Regular Expression,简称regex)是一种用于描述字符串结构的语法规则。它定义了一个搜索模式,可以用来匹配、替换或提取文本中的子串。正则表达式广泛应用于文本处理、数据验证、查找和替换等场景。
正则表达式的语法规则
正则表达式由元字符 (metacharacters)和文本字符(literal characters)两部分构成。元字符具有特殊的功能,而文本字符则是普通的字符。
元字符
^:匹配行的开始位置。$:匹配行的结束位置。.:匹配除换行符之外的任何单个字符。[]:字符类,用于匹配某个范围内的字符。|:选择符,表示"或"。\:转义字符,用于转义元字符,或者表示一些预定义字符类。():分组和捕获。{}:限定符,指定前面的字符重复出现的次数。
例子
regex
/\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/ # 一个常见的邮箱匹配表达式
为了简化表达和更易阅读,后续我们省略掉定界符(/)部分,直接呈现正则表达式的核心内容。
常见元字符与用法
行定位符
^:匹配字符串的开始。例如,^tm会匹配行首的tm。$:匹配字符串的结束。例如,tm$会匹配行尾的tm。
单词定界符
\b:匹配一个单词的边界,表示匹配完整的单词。例如,\btm\b会匹配独立的tm。\B:与\b相反,表示不匹配单词边界。
字符类
[abc]:匹配方括号中的任意单个字符,如a、b或c。[^abc]:匹配不在方括号中的字符,如除了a、b或c外的任何字符。
预定义字符类
\d:匹配任意一个数字,等同于[0-9]。\D:匹配非数字字符,等同于[^0-9]。\w:匹配任意一个字母、数字或下划线,等同于[a-zA-Z0-9_]。\W:匹配非字母、非数字和非下划线字符。\s:匹配任意一个空白字符(包括空格、制表符、换行符等)。\S:匹配非空白字符。
限定符
?:匹配前面的字符零次或一次。例如,colou?r可以匹配color和colour。+:匹配前面的字符一次或多次。例如,go+gle可以匹配gogle、googgle等。*:匹配前面的字符零次或多次。例如,go*gle可以匹配gle、google、googgle等。{n}:匹配前面的字符恰好 n 次。例如,go{2}gle只会匹配google。{n,}:匹配前面的字符至少 n 次。例如,go{2,}gle可以匹配google、googgle等。{n,m}:匹配前面的字符至少 n 次,最多 m 次。例如,employe{0,2}可以匹配employ、employe和employee。
选择字符(|)
|:表示"或"操作。例如,(T|t)(M|m)可以匹配TM、Tm、tM或tm。
连字符(-)
-:表示字符范围。例如,[a-zA-Z]可以匹配任何大小写字母。
括号字符(())
():用于分组。例如,(thir|four)th可以匹配thirth或fourth。- 分组的作用不仅仅是捕获子表达式,还能影响其他操作符(如
*、+等)的应用范围。 (?: ... ):非捕获组,用于分组,但不捕获匹配的内容,可以提高性能,并避免捕获组编号的混乱。
转义字符(\)
\:用来转义元字符,使其失去特殊意义。例如,\.匹配字面上的点号.。- 反斜线还可以用于表示一些特殊字符或定义字符集:
\d表示数字,\s表示空白字符等。
断言(环视)
断言用于匹配某些位置,不会消耗字符,但可以检查字符的上下文。
- 顺序环视(前瞻) :
(?=...),表示匹配前面必须跟着某个子串。例如,\s(?=is)匹配空格,后面紧跟着is。 - 逆序环视(后顾) :
(?<=...),表示匹配前面有某个子串。例如,(?<=is)\s匹配is后面的空格。
模式修饰符
模式修饰符用于修改正则表达式的行为。
i:忽略大小写。例如,/abc/i可以匹配abc、ABC等。m:多行模式,影响^和$的行为,使其匹配每一行的开始和结束。s:单行模式,使.能够匹配换行符。x:忽略正则表达式中的空格,方便书写复杂的正则。
拓展:正则表达式引擎
正则表达式引擎(Regular Expression Engine)是用于执行正则表达式匹配和替换操作的软件组件。它接收正则表达式和输入文本作为输入,输出是否匹配的结果,或者返回匹配的部分内容。不同的编程语言和工具提供了不同类型的正则表达式引擎,它们根据底层实现的不同,可能在性能和特性上有所差异。
常见术语
grep:最初是 Unix 系统中的一个命令,用于在文件中搜索特定的内容。后来它成为一个独立的工具,用于处理文本数据。egrep:是grep命令的扩展版本,增强了正则表达式的能力,支持更复杂的模式匹配。POSIX:是可移植操作系统接口的标准,它并不是最终的标准,而是为确保操作系统之间的可移植性提供的参考。Perl:是实际抽取与汇报语言,POSIX标准之后的另一种正则表达式标准。PCRE:即兼容 Perl 正则表达式的正则引擎,支持更强大的功能,并可以整合到 PHP 等其他语言中。
正则表达式引擎的主要类型
-
NFA(Non-deterministic Finite Automaton)
非确定性有限自动机(NFA)是一种较为常见的正则表达式引擎实现方式。NFA 引擎根据状态转移图的概念工作,并且可以有效地处理很多常见的正则表达式操作。NFA 引擎的工作原理是:它尝试将输入字符串与正则表达式从左到右进行匹配,使用状态机的方式进行尝试。
- 优点:NFA 引擎具有灵活性,能够轻松处理多种复杂的正则表达式。
- 缺点:在处理某些复杂或不常见的正则表达式时,可能导致性能较差,特别是在匹配非常长的文本时。
-
DFA(Deterministic Finite Automaton)
确定性有限自动机(DFA)与 NFA 相对,它的状态转移图更为简单和明确,每个状态只有一个唯一的后续状态。DFA 引擎的实现通常比 NFA 更为高效,尤其是在文本匹配时。
- 优点:DFA 引擎通常能够提供较高的匹配速度,因为它在匹配时只有一个确定的路径。
- 缺点:DFA 引擎的设计通常要求更多的内存,特别是当正则表达式的模式非常复杂时。
-
回溯(Backtracking)
回溯引擎是一种常见的正则表达式引擎实现方式,尤其在如 PCRE(Perl Compatible Regular Expressions)等工具中得到了广泛应用。回溯引擎通过递归地尝试各种匹配路径来寻找符合正则表达式模式的子串。它会从开始状态尝试每一种可能的匹配路径,直到找到匹配或确认没有匹配。
- 优点:回溯引擎灵活,能够处理复杂的正则表达式模式。
- 缺点:在某些情况下,回溯引擎可能会导致性能下降,特别是在处理复杂的表达式时,可能出现所谓的"灾难性回溯"问题(例如,正则表达式包含多个可能的匹配路径,导致大量的无效计算)。
-
正则表达式虚拟机(REVM)
正则表达式虚拟机是某些正则表达式引擎使用的另一种技术。它将正则表达式转化为一种类似于程序代码的格式,然后执行该代码进行匹配。REVM 主要通过编译将正则表达式转换为某种中间代码,再通过虚拟机解释执行该中间代码。
- 优点:这种方法可以结合编译和解释的优点,可能在某些情况下提高匹配速度。
- 缺点:这种方法的实现较为复杂,需要在引擎中进行更多的计算和转换。
常见正则表达式引擎
-
PCRE(Perl Compatible Regular Expressions)
PCRE 是一种流行的正则表达式引擎,它与 Perl 语言的正则表达式兼容,广泛用于 PHP、Apache、NGINX 等开源项目。PCRE 引擎使用回溯算法,支持丰富的正则语法。
-
RE2
RE2 是 Google 提供的一个正则表达式引擎,设计目标是提供一个高效且没有回溯的正则匹配功能。RE2 引擎通常能够避免性能陷阱,适合处理大规模数据集。
-
JavaScript 引擎(如 V8 引擎)
JavaScript 引擎(例如 V8)实现了正则表达式的支持,通常使用回溯算法。它是现代浏览器中常见的正则表达式引擎。
-
Python 正则表达式(re 模块)
Python 的
re模块使用回溯算法来实现正则匹配。它支持 Perl 风格的正则语法,灵活且易用。 -
.NET 正则表达式引擎
.NET 提供了强大的正则表达式支持,内置于
System.Text.RegularExpressions类库中,采用回溯引擎。它支持多种正则表达式功能,并且优化了性能,适合 .NET 平台使用。 -
POSIX 正则表达式
POSIX 标准为 Unix-like 系统提供了一个正则表达式的标准。与其他正则表达式引擎相比,POSIX 更注重跨平台的兼容性,但在性能和特性上相对较弱。
例如,在 PHP 中,正则表达式支持两种格式:POSIX 和 PCRE。其中,PCRE(Perl Compatible Regular Expressions)兼容 Perl 风格的正则表达式,是 PHP 中最常用的正则引擎。
小结
正则表达式是强大的文本处理工具,通过掌握其基本语法规则,可以方便地对字符串进行匹配、查找和替换等操作。掌握元字符、限定符、断言等功能,能够帮助我们构建更精确和高效的正则表达式。
正则表达式的学习需要耐心,理解每个元字符的含义以及如何组合它们来构建复杂的匹配模式是掌握正则的关键。