R / Richie全部文章 ↑

Python · 5 分钟阅读

`re`:正则表达式

目录


正则表达式(Regular Expression)是字符串模式匹配的强大工具。Python 的
re 模块把它完整带到了标准库,并提供匹配、搜索、替换、分割等核心能力。

能用 str 方法就别用正则(如 s.startswith / s.endswith /
s.split);正则可读性差、维护成本高。能用结构化解析就别用正则
(HTML 用 lxml、JSON 用 json、配置文件用 pyyaml/tomllib)。


1. 导入

import re

2. 四个最常用函数

函数 作用
re.search(pattern, s) 找第一个匹配,返回 Match 或 None
re.match(pattern, s) 从开头匹配
re.findall(pattern, s) 返回所有匹配(列表)
re.finditer(pattern, s) 返回所有匹配(迭代器)
re.sub(pattern, repl, s) 替换
re.split(pattern, s) 按模式分割
import re

m = re.search(r"cat", "The cat is on the roof.")
if m:
    print(m.group())            # 'cat'
    print(m.start(), m.end())   # 4 7

建议给模式加 r"..." 前缀(原始字符串),避免 \ 转义噩梦。


3. compile:重复使用同一个模式

word3 = re.compile(r"\b\w{3}\b")
print(word3.findall("The cat is on the roof."))
# ['The', 'cat', 'the']

re.compile() 后还能直接调用方法(p.search(s)、p.findall(s)),省去
每次解析模式的开销,写库 / 高频场景强烈建议。


4. 常用语法

4.1 字符匹配

模式 含义
. 任意字符(除换行)
\d / \D 数字 / 非数字
\w / \W 单词字符 [A-Za-z0-9_] / 非单词字符
\s / \S 空白 / 非空白
[abc] 字符类
[^abc] 排除
[a-z] 范围

4.2 边界

模式 含义
^ 字符串开头
$ 字符串结尾
\b 单词边界
\B 非单词边界

4.3 量词

模式 含义
* 0 次或多次
+ 1 次或多次
? 0 次或 1 次
{n} 恰好 n 次
{n,} 至少 n 次
{n,m} n ~ m 次
*? / +? / ?? 非贪婪(尽量少匹配)

4.4 分组与引用

# () 分组,(?P<name>...) 命名分组
m = re.match(r"(?P<year>\d{4})-(?P<month>\d{2})", "2026-08")
m.group("year")         # '2026'
m.group(2)               # '08'(按编号从 1 开始)
m.groupdict()            # {'year': '2026', 'month': '08'}

反向引用:替换时用 \1 / \g<name>:

re.sub(r"(\w+) \1", r"\1", "hello hello world")   # 'hello world'

4.5 断言(不占字符)

模式 含义
(?=...) 正向先行:后面是 …
(?!...) 负向先行:后面不是 …
(?<=...) 正向后顾:前面是 …
(?<!...) 负向后顾:前面不是 …
# 提取以 .py 结尾的单词(不包含 .py)
re.findall(r"\b\w+(?=\.py\b)", "main.py lib.py data.json")
# ['main', 'lib']

5. re.sub 的回调替换

def double(m):
    return str(int(m.group()) * 2)

re.sub(r"\d+", double, "a1 b22 c333")
# 'a2 b44 c666'

比 f-string 写死的复杂替换更灵活。


6. flags

标志 含义
re.IGNORECASE / re.I 忽略大小写
re.MULTILINE / re.M ^ / $ 匹配每行
re.DOTALL / re.S . 匹配换行
re.VERBOSE / re.X 模式里可以写注释 / 空白
re.ASCII / re.A \w 等只匹配 ASCII
re.search(r"^hello", "Hello world", re.IGNORECASE)        # 匹配
pattern = re.compile(r"""
    (?P<area>\d{3})-
    (?P<first>\d{4})
""", re.VERBOSE)

7. 实战:从一段文本里抽取所有邮箱

import re

text = """
请联系 support@example.com 或 sales@foo-bar.co.uk;
无效的如 hello@, @world.com 不会被匹配。
"""

EMAIL = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
print(EMAIL.findall(text))
# ['support@example.com', 'sales@foo-bar.co.uk']

“真要 100% 准确请用 email-validator 库”;正则匹配只是“看起来像”。


8. 常见误区

  • re.match 只匹配开头:要全文搜索请用 re.search。
  • 贪婪 vs 非贪婪:.* 会尽量长,匹配错了就改用 .*?。
  • 转义混乱:永远是 r"..." 原始字符串写模式。
  • 性能:高频匹配一定要 re.compile;re.findall 返回列表,大文本用
    finditer
    流式处理。
  • 复杂模式拆分:把长正则拆成几行 + re.VERBOSE,可读性会好很多。
  • 不要用正则解析 HTML:标签会嵌套,正则很容易写出 bug。用 lxml / BeautifulSoup。

9. 第三方补充

  • regex:第三方正则库,支持更多特性(递归、模糊匹配等)。
  • pyparsing:真正需要写“语法”时用它。
  • lark:现代的解析器组合子库。

10. 小结

  • re 是 Python 标准库的正则;绝大多数字符串匹配问题都能解决。
  • 高频匹配 先 compile;长模式用 re.VERBOSE 拆开。
  • 分组、命名、断言、回调替换是四个“提升可读性”的关键武器。
  • 能用字符串方法 / 库就 别 用正则,别 拿正则解析 HTML。