Python 正则表达式(Regular Expression)的艺术
正则表达式是处理字符串的“瑞士军刀”,但它也是 Python 中最容易让人又爱又恨的工具之一。
2025–2026 年在实际工程中,正则的使用频率其实并没有显著下降,反而因为日志解析、数据清洗、爬虫、配置文件解析、代码生成等场景,仍然是高频工具。
下面从实用角度整理一份当前最值得掌握的正则知识体系(偏向“能解决真实问题”而非“记住所有语法”)。
一、先记住这 8 种最常用的模式(占实际使用 80%+)
| 序号 | 模式写法示例 | 含义 | 最常见使用场景 | Python 代码示例 |
|---|---|---|---|---|
| 1 | \d+ | 一个或多个数字 | 提取数字、ID、价格、手机号 | re.findall(r’\d+’, text) |
| 2 | [a-zA-Z0-9_-]+ | 常见的“单词字符”组合 | 用户名、变量名、key、slug | re.match(r’^[a-zA-Z0-9_-]+$’, username) |
| 3 | [^@]+@[^@]+\.[^@]+ | 非常粗糙但常用的邮箱校验 | 表单校验(生产环境建议更严格) | re.search(r'[^@]+@[^@]+.[^@]+’, email) |
| 4 | https?://[^\s<>"']+ | 匹配 http/https 链接 | 从文本中提取链接 | re.findall(r’https?://[^\s<>”\’]+’, text) |
| 5 | [\u4e00-\u9fa5]+ | 匹配中文字符 | 中文分词前过滤、提取中文内容 | re.findall(r'[\u4e00-\u9fa5]+’, text) |
| 6 | (\d{4})-(\d{2})-(\d{2}) | 捕获分组 – 日期 | 结构化提取年月日 | match = re.match(r'(\d{4})-(\d{2})-(\d{2})’, s) |
| 7 | (?P<year>\d{4})-(?P<month>\d{2}) | 命名捕获组(推荐) | 可读性更高的分组提取 | match.group(‘year’), match.group(‘month’) |
| 8 | .*? 或 .*?(?=后缀) | 非贪婪匹配 + 正向肯定预查 | 提取两个标记之间的内容(最实用技巧) | re.search(r’start(.*?)end’, text, re.DOTALL) |
二、Python 中最常用的 6 个 re 函数(记住这 6 个就够用了)
| 函数 | 主要用途 | 返回值类型 | 是否常用 | 典型写法示例 |
|---|---|---|---|---|
re.match(pattern, string) | 从开头匹配 | Match 或 None | ★★★★ | re.match(r’^\d+’, line) |
re.search(pattern, string) | 在任意位置找到第一个匹配 | Match 或 None | ★★★★★ | re.search(r’\d{11}’, text) |
re.findall(pattern, string) | 找到所有非重叠匹配 | list[str] 或 list[tuple] | ★★★★★ | re.findall(r’\d+’, “abc123def456”) → [‘123′,’456’] |
re.finditer(...) | 返回所有匹配的 Match 迭代器 | iterator[Match] | ★★★ | for m in re.finditer(r’\w+’, text): … |
re.sub(pattern, repl, string) | 替换匹配到的内容 | 新字符串 | ★★★★ | re.sub(r’\s+’, ‘-‘, title) |
re.split(pattern, string) | 用正则切分字符串 | list[str] | ★★★ | re.split(r'[,;]\s*’, “a, b;c ,d”) |
三、2025–2026 年最实用的“正则三件套”写法模板
import re
# 模板1:安全提取(推荐写法)
def extract_phone(text):
pattern = r'(?:1[3-9]\d{9})|\b0\d{2,3}[- ]?\d{7,8}\b'
return re.findall(pattern, text)
# 模板2:命名组 + 结构化提取(日志/配置解析神器)
log_line = "2025-03-23 10:15:22 [INFO] user_id=12345 action=login ip=192.168.1.100"
pattern = r'(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?P<level>\w+)\] .+user_id=(?P<uid>\d+)'
m = re.search(pattern, log_line)
if m:
print(m.groupdict()) # {'time': '...', 'level': 'INFO', 'uid': '12345'}
# 模板3:非贪婪 + 预查(最常用来提取“两端之间”的内容)
html = '<div class="content">重要信息在这里</div><p>其他</p>'
content = re.search(r'<div class="content">(.*?)</div>', html, re.DOTALL)
print(content.group(1) if content else "未找到")
四、正则常见“优雅 vs 灾难”对比(避坑指南)
| 场景 | 灾难写法(容易出问题) | 优雅写法(推荐) | 为什么更好 |
|---|---|---|---|
| 匹配任意字符 | .* | .*? + re.DOTALL 或 [\s\S]*? | 避免贪婪匹配吃太多内容 |
| 多行匹配 | 没加 re.DOTALL | re.DOTALL 或 re.MULTILINE | . 默认不匹配换行 |
| 性能爆炸 | (.*)+ 或 (a?)* | 改用具体字符类 + 非贪婪 | 避免灾难性回溯(catastrophic backtracking) |
| 邮箱校验(简单版) | .*@.*\..* | r'[^@]+@[^@]+.[^@]{2,}$’ | 更不容易误匹配 |
| 中文 + 英文混合提取 | [\w\u4e00-\u9fa5]+ | [\w\u4e00-\u9fa5]+ + 必要时加 re.UNICODE | Python 3 默认支持 Unicode |
五、2026 年建议的学习 & 使用策略
- 前 3 周:只练最常用的 8 个模式 + 6 个函数
- 工具推荐:
- regex101.com(必备调试神器,选 Python flavor)
- Pythex.org
- VSCode 正则查找替换(直接测试)
- 推荐进阶顺序:
- 先掌握基础提取 → 再学替换 → 再学命名组 → 最后看零宽断言(lookaround)
- 生产建议:
- 能用字符串方法 / split / join 解决的,优先不用正则
- 复杂正则一定要写注释 + 测试用例
- 考虑用第三方库:parsimonious、re2(更快)、regex(增强版)
你现在是用正则来解决什么具体问题?
(日志解析?爬虫?数据清洗?配置读取?表单校验?……)
告诉我场景,我可以直接给你针对性的正则写法 + 测试代码。