Python正则表达式匹配与替换实操指南

花开有时
花开有时
发布时间:2026-10-10 | 2人浏览过
原创

本文详解 Python re 模块核心用法,涵盖基础元字符到复杂文本替换。通过 match、search、findall 实现精准提取,利用 sub 结合分组与回调完成批量修改。提供日志解析、数据脱敏场景代码及 compile 性能优化方案,助开发者高效处理非结构化文本。

核心目标与准备条件

正则表达式用于在文本中快速定位、提取和修改特定模式。使用 Python 前需确认已安装标准运行环境,re 为内置模块,无需额外安装。

第1步:导入基础模块

目的:启用正则引擎以便后续调用匹配与替换函数。
入口:脚本或交互环境首行
动作:执行 import re
完成状态:控制台无报错且模块加载成功,可立即使用 re.xxx() 系列方法。

import re

常用匹配方法操作

re.match() - 限定开头匹配

仅校验字符串起始位置是否符合规则。若文本模式可能出现在中间或末尾,该函数将返回 None。

text = "Hello World 2024"
result = re.match(r"Hello", text)
if result:
    print("匹配成功:", result.group())  # 输出: Hello

re.search() - 首次全文搜索

从左至右扫描整段文本,返回首个命中的匹配对象。适用于快速提取关键字段。

text = "The year is 2024"
result = re.search(r"\d{4}", text)
if result:
    print("找到数字:", result.group())  # 输出: 2024

re.findall() / re.finditer() - 全量提取

需要获取所有符合条件片段时选择。前者直接返回字符串列表;后者返回迭代器,携带每组匹配的跨度索引 span(),更适合内存受限的大文本处理。

# findall 直接输出列表
prices = re.findall(r"\d+元", "苹果10元, 香蕉5元, 橙子8元")
print(prices)  # ['10元', '5元', '8元']

# finditer 携带位置索引,便于后续切片或替换
for m in re.finditer(r"\d{3}-\d{4}", "联系: 123-4567, 987-6543"):
    print(f"电话: {m.group()} 位于: {m.span()}")

字符串替换与分组应用

re.sub() 基础替换

直接替换文本中首次出现的旧内容,支持指定替换次数。

new_text = re.sub(r"2023", "2024", "今天是2023年12月15日")
print(new_text)  # 今天是2024年12月15日

分组引用与回调处理

圆括号 () 定义捕获组,替换时可通过 \1、\2 反向引用重组结构。当替换逻辑包含计算或条件判断时,可直接传入自定义函数,其返回值将作为新片段。

def double_number(match):
    return str(int(match.group()) * 2)

# 交换姓名顺序
name_swap = re.sub(r"(\w+) (\w+)", r"\2 \1", "张三 李四 王五")
print(name_swap)  # 李四 张三 王五

# 数值翻倍回调
val_double = re.sub(r"\d+", double_number, "数字: 5, 10, 15")
print(val_double)  # 数字: 10, 20, 30

典型业务场景实战

统一电话号码格式

忽略中间的连接符(空格、横杠、点),强制转换为标准区号-号码结构,兼容多种输入习惯。

pattern = r"(\d{3})[-.\s]?(\d{3})[-.\s]?(\d{4})"
replacement = r"(\1) \2-\3"
formatted = re.sub(pattern, replacement, "123-456 7890")
print(formatted)  # 输出: (123) 456-7890

清理 HTML 标签

匹配尖括号及其内部任意非闭合字符,剥离标记符号保留纯文本内容。

clean_text = re.sub(r"<[^>]+>", "", "<h1>标题</h1><p>这是一个段落</p>")
print(clean_text)  # 输出: 标题这是一个段落

敏感数据脱敏

保留首尾固定位数,中间用星号遮蔽。常用于身份证号、手机号等合规处理需求。

def mask_sensitive_data(text):
    text = re.sub(r"(\d{4})\d{8}(\d{4})", r"\1********\2", text)
    text = re.sub(r"(\d{3})\d{4}(\d{4})", r"\1****\2", text)
    return text

sensitive = "身份证: 510123199001011234, 手机: 13800138000"
print(mask_sensitive_data(sensitive))  # 身份证: 5101********1234, 手机: 138****8000

解析结构化日志

按固定分隔线提取时间戳、日志级别与详情,转化为字典列表供下游系统分析。

log_pattern = r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) [(\w+)] (.+)"
parsed_logs = []
for line in log_content.split('\n'):
    match = re.match(log_pattern, line)
    if match:
        timestamp, level, message = match.groups()
        parsed_logs.append({'timestamp': timestamp, 'level': level, 'message': message})

性能优化与进阶技巧

编译正则提升执行效率

对循环内或高频调用的模式预先编译,减少底层引擎的重解析开销。编译后的对象可直接复用 search/match/sub 等方法。

phone_pattern = re.compile(r"(\d{3})-(\d{3})-(\d{4})")
texts = ["123-456-7890", "987-654-3210"]
for text in texts:
    m = phone_pattern.search(text)
    if m:
        print(f"完整匹配: {m.group()}, 分组: {m.groups()}")

命名分组、非贪婪与后查找

使用 (?P<name>...) 替代数字索引,大幅提升代码可读性;在量词后添加 ? 启用非贪婪模式,防止过度消耗相邻字符;配合 (?<=...) 正向后查找可精准定位前置条件后的目标串。

# 非贪婪提取独立标签块
groups = re.findall(r"<div>(.*?)</div>", "<div>内容1</div><div>内容2</div>")
print(groups)  # ['内容1', '内容2']

# 正向后查找提取价格数字
prices = re.findall(r"(?<=\$)\d+", "Price: $100, Discount: $20")
print(prices)  # ['100', '20']

注意事项与总结

  1. 编写正则时务必使用原始字符串 r"...",避免反斜杠转义冲突。
  2. 在循环或高频场景中,优先使用 re.compile() 缓存模式对象。
  3. 仅涉及固定子串切割或替换时,Python 原生 split/replace 性能更优,勿盲目依赖正则。

正则表达式是 Python 处理文本流的基石工具。掌握 re 模块的匹配策略、分组控制与替换机制,配合编译优化与高级语法,可显著降低数据清洗、日志审计与格式化任务的开发成本。以上就是 Python 正则表达式匹配和替换操作的详细内容,更多关于 Python 正则表达式与文本处理技术的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表