正则表达式用普通字符与元字符组合定义字符串匹配规则,是文本搜索、替换、验证的通用工具。语法跨语言高度一致,本文介绍来源和基础语法;

Python 标准库的 API 用法单独成篇,见 Python re 模块

正则表达式(Regular Expression),中文叫;口语简写还有 regex / regexp。Python 的标准库直接取名 re

这里的**正则(regular)来自自动机理论里的 ** 正则集(regular set),不是“合乎规则”这种日常中文理解。

  1. 1956 数学家 Stephen Kleene 提出正则代数,用来描述一类有限自动机能识别的语言集合,这种集合就叫 regular set,描述它的式子叫 regular expression。

    regular 在数学里含义:可由有限状态自动机描述的集合,翻译时译作「正则」。

  2. 后续 Ken Thompson(Unix之父)把这套数学理论搬到 Unix 的文本编辑器 ed,诞生了 g/re/p 命令(global / regular expression / print,也就是后来的grep),正则正式进入计算机世界。

容易踩坑: 中文名字里的正则是数学术语翻译,不要理解成“正规、正确的表达式”。它特指正则语言对应的表达式。

元字符速查

元字符含义示例
.任意单字符(默认不含换行)a.c → abc, a1c
^字符串开头^The
$字符串结尾end$
*0次或多次ab* → a, ab, abbb
+1次或多次ab+ → ab, abbb
?0次或1次ab? → a, ab
{n}精确n次a{3} → aaa
{n,m}n到m次a{2,4}
|cat|dog → cat, dog
[]字符集[aeiou], [0-9]
()分组捕获(abc)+

转义序列与元字符配合使用,出现频率同样高:

转义含义等价写法
\d / \D数字 / 非数字[0-9] / [^0-9]
\w / \W单词字符 / 非单词字符[a-zA-Z0-9_]
\s / \S空白 / 非空白[ \t\n\r\f\v]
\b单词边界

贪婪与惰性

用来规定前面那个模式,要匹配多少次的词,称为”量词“。它跟在一个字符/字符组/分组后面,控制重复次数。

量词含义
*0次或多次(≥0)
+1次或多次(≥1)
?0次或1次(最多1次)
{n}恰好 n 次
{n,}至少 n 次
{n,m}n ~ m 次

量词默认贪婪:尽可能多匹配,再回溯让出字符;量词后加 ?惰性,只取满足条件的最短匹配。提取 HTML 标签是经典对照:

import re
 
re.findall(r'<.*>', '<a>hi</a><b>yo</b>')   # ['<a>hi</a><b>yo</b>'] 贪婪,整行吞掉
re.findall(r'<.*?>', '<a>hi</a><b>yo</b>')  # ['<a>', '</a>', '<b>', '</b>'] 惰性,逐个标签
  • .+ 量词 + 贪婪
  • 引擎:从<开始,.一口气吞到字符串末尾
  • 发现末尾没有>回溯,吐出字符,直到找到第一个>
  • 匹配结果:<a> <b>(一次性抓到最后那个>)

Note

量词 = 控制前面的规则重复多少次;默认贪心拿最多,加问号改成拿最少。

常用模式

# 邮箱
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
 
# 中国手机号
^1[3-9]\d{9}$
 
# 日期 YYYY-MM-DD
^\d{4}-\d{2}-\d{2}$
 
# URL
^(https?://)?(www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(/.*)?$

高级特性

特性语法用途
非捕获分组(?:abc)仅匹配,不保存
命名分组(?P<name>abc)按名引用捕获内容
反向引用(\w)\1复用先前分组(匹配叠字等)
正向前瞻(?=abc)后面是 abc
负向前瞻(?!abc)后面不是 abc
正向后瞻(?<=abc)前面是 abc
负向后瞻(?<!abc)前面不是 abc

前瞻后瞻是零宽断言:只判断位置、不消耗字符,因此同一位置可叠加多个条件。密码强度校验是典型应用——同时要求含数字、小写、大写:

(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\S{8,}

各语言实现

正则语法存在方言差异(PCRE、POSIX、JavaScript 各有出入),元字符语义大体一致但细节不同。Python re 模块的完整用法——函数选择、命名分组取值、re.sub 函数替换、flags 与编译复用——见 Python re 模块

现代 Perl、Python 的正则已经超出原始 Kleene 的正则语言范围(增加反向引用、环视等,能力升级到上下文无关语法),只是名字沿用历史,依旧叫 Regular Expression。