模式生成与向量格式教程:第 4 章 Python re 模块实战

说到正则表达式,在 Python 里干活,绕不开的就是 re 模块。很多人觉得正则难,其实不是语法难,是不知道用什么函数去匹配。

今天我们就来聊聊 re 模块里的四大金刚:re.match、re.search、re.findall 和 re.sub。我会把每个函数在什么时候用、怎么用,以及我踩过的坑都讲清楚。

1. re.match —— 从开头开始

说白了,re.match 只匹配字符串的开头。它就像个守门员,只在门口检查。

我来举个例子:

import re

text = "Hello World! Hello Python!"
result = re.match(r"Hello", text)
if result:
    print(result.group())  # 输出: Hello

result2 = re.match(r"World", text)
print(result2)  # 输出: None

为什么会这样?因为 World 不在开头。我在日志分析项目里用过很多次,比如检查一行日志是不是以 "ERROR" 开头。用 re.match 就特别合适。如果你需要匹配中间的内容,别用这个。

我的习惯:检查字符串前缀或协议头时,用 re.match 比用 str.startswith() 更灵活,因为它支持正则模式。

2. re.search —— 全局搜索

re.search 就灵活多了。它在整个字符串中搜索,找到第一个匹配就停下来。你想想看,如果要在文本里找电话号码或者邮箱,用这个最合适。

text = "我的邮箱是 alice@example.com,备用邮箱是 bob@test.org"
match = re.search(r"\w+@\w+\.\w+", text)
if match:
    print(match.group())  # 输出: alice@example.com

注意,它只返回第一个匹配。要是你想找所有的邮箱,那就得用下一个函数了。

我曾经在一个爬虫项目里,只用了 re.search 来提取所有链接,结果只拿到一个。后来才意识到,应该用 re.findall。

3. re.findall —— 全部提取

嗯,这里要注意。re.findall 返回所有非重叠匹配的列表。如果模式里有分组,它返回的是元组列表。

text = "手机号: 13800138000, 13912345678"
numbers = re.findall(r"1[3-9]\d{9}", text)
print(numbers)  # 输出: ['13800138000', '13912345678']

# 有分组的情况
text2 = "alice@example.com, bob@test.org"
matches = re.findall(r"(\w+)@(\w+\.\w+)", text2)
print(matches)  # 输出: [('alice', 'example.com'), ('bob', 'test.org')]

我个人习惯在处理日志或者爬虫数据时,优先用 re.findall。它帮你一次性提取完所有目标数据,效率很高。

函数 作用 返回值 适用场景
re.match 从开头匹配 Match 对象或 None 检查前缀
re.search 查找第一个匹配 Match 对象或 None 查找单个目标
re.findall 查找所有匹配 列表(或元组列表) 批量提取
re.sub 替换匹配的文本 替换后的字符串 文本清理

4. re.sub —— 替换与清洗

最后这个,re.sub,是文本处理的大杀器。它做的事情很简单:找到匹配的内容,换成你指定的新内容。

text = "今天是2025年01月01日,明天是01月02日"
new_text = re.sub(r"\d{4}年", "2026年", text)
print(new_text)  # 输出: 今天是2026年01月01日,明天是01月02日

# 更复杂的用法:使用回调函数
def replace_date(match):
    month = match.group(1)
    day = match.group(2)
    return f"{day}月{month}日"

text2 = "日期: 05-20, 12-25"
result = re.sub(r"(\d{2})-(\d{2})", replace_date, text2)
print(result)  # 输出: 日期: 20月05, 25月12

嗯,有一次我同事没注意替换的边界,结果把不该改的词也改掉了。用 re.sub 时,正则要写得精准,不然容易误伤。

核心要点:re.sub 还可以指定替换次数,通过 count 参数控制。默认替换所有匹配,改成 count=1 就只替换第一个。

知识体系图谱

下面这张图总结了这四种函数的核心逻辑和关系:

Python re 模块核心函数关系图 Python re 模块四大核心函数 正则表达式引擎 re.match 从开头匹配 re.search 查找第一个 re.findall 提取所有 re.sub 替换文本 输出结果类型 Match对象 / None · 列表 · 替换后字符串 充分理解 match、search、findall、sub 的差异

实际项目中的建议

我建议你在开发前,先想清楚目标:是检查开头(match)、找单个目标(search)、提取所有(findall)还是做替换(sub)。选错函数,代码就得不偿失。

  • 验证输入格式:用 re.match(如检查手机号开头是否是 1)。
  • 提取第一个关键信息:用 re.search(如从一大段文字里找第一个日期)。
  • 爬虫或日志解析:用 re.findall 批量抓取。
  • 数据清洗:用 re.sub 替换脏数据或格式化文本。

还有一个容易被忽略的点:预编译正则。如果你要反复使用同一个模式,先 re.compile 一下,能提升不少性能。

# 预编译示例
pattern = re.compile(r"\d{3}-\d{8}")
texts = ["010-12345678", "021-87654321"]
for t in texts:
    match = pattern.search(t)
    if match:
        print(match.group())
我曾经在处理上万条日志时没用预编译,结果跑了好几分钟。后来改成预编译,几十秒就搞定了。这种细节,能省就省吧。

好了,这四种函数基本覆盖了日常 90% 的正则需求。记住它们的差异,写代码的时候就不会犹豫了。