正则表达式是文本处理的核心工具,几乎所有编程语言都支持。这篇整理常用语法和Python中re模块的实际用法,方便随时查阅。
元字符速查
| 符号 | 含义 | 示例 |
|---|---|---|
. |
任意字符(除换行) | a.c 匹配 abc, a1c |
\d |
数字 [0-9] | \d{3} 匹配 123 |
\w |
字母数字下划线 | \w+ 匹配 hello_123 |
\s |
空白字符 | a\sb 匹配 a b |
\D \W \S |
上面三个的取反 | |
^ |
行首 | ^Hello |
$ |
行尾 | world$ |
\b |
单词边界 | \bcat\b 不匹配 catch |
量词
| 符号 | 含义 |
|---|---|
* |
0次或多次 |
+ |
1次或多次 |
? |
0次或1次 |
{n} |
恰好n次 |
{n,} |
至少n次 |
{n,m} |
n到m次 |
默认是贪婪匹配(尽可能多),加?变成非贪婪:
import re
text = "<b>bold</b> and <i>italic</i>"
re.findall(r"<.*>", text) # ['<b>bold</b> and <i>italic</i>'] 贪婪
re.findall(r"<.*?>", text) # ['<b>', '</b>', '<i>', '</i>'] 非贪婪
分组与捕获
import re
# 基本分组
m = re.match(r"(\d{4})-(\d{2})-(\d{2})", "2021-02-18")
print(m.group(0)) # 2021-02-18 (整体匹配)
print(m.group(1)) # 2021
print(m.group(2)) # 02
# 命名分组
m = re.match(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})", "2021-02-18")
print(m.group("year")) # 2021
# 非捕获分组(只分组不捕获)
re.findall(r"(?:https?://)?(\w+\.\w+)", "https://example.com http://test.org")
# ['example.com', 'test.org']
零宽断言
不消耗字符,只匹配位置:
# 正向前瞻 (?=...):后面是...
re.findall(r"\w+(?=@)", "user@example.com") # ['user']
# 负向前瞻 (?!...):后面不是...
re.findall(r"\d+(?!px)", "12px 34em 56") # ['34', '56']
# 正向后顾 (?<=...):前面是...
re.findall(r"(?<=\$)\d+", "price $100") # ['100']
# 负向后顾 (?<!...):前面不是...
re.findall(r"(?<!\d)\d{3}(?!\d)", "12 123 1234") # ['123']
Python re模块
import re
text = "联系电话: 13812345678, 备用: 13987654321"
# findall: 找所有匹配
phones = re.findall(r"1[3-9]\d{9}", text)
# ['13812345678', '13987654321']
# search: 找第一个匹配
m = re.search(r"1[3-9]\d{9}", text)
print(m.group()) # 13812345678
# sub: 替换
masked = re.sub(r"(1\d{2})\d{4}(\d{4})", r"\1****\2", text)
# "联系电话: 138****5678, 备用: 139****4321"
# split: 按模式分割
parts = re.split(r"[,;\s]+", "a, b; c d")
# ['a', 'b', 'c', 'd']
# compile: 预编译(多次使用时提升性能)
pattern = re.compile(r"\d{4}-\d{2}-\d{2}")
dates = pattern.findall("日期: 2021-02-18, 截止: 2021-03-01")
常用正则模式
# 邮箱
r"[\w.+-]+@[\w-]+\.[\w.]+"
# 手机号
r"1[3-9]\d{9}"
# URL
r"https?://[\w\-._~:/?#\[\]@!$&'()*+,;=%]+"
# IP地址
r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
# 身份证号
r"\d{17}[\dXx]"
小结
正则不需要全记住,掌握基本元字符、量词、分组就能覆盖80%的场景。遇到复杂的正则,推荐用 regex101.com 在线调试——可视化的匹配过程比自己脑内解析高效多了。