Python正则表达式匹配与替换实操指南
本文详解 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']
注意事项与总结
- 编写正则时务必使用原始字符串
r"...",避免反斜杠转义冲突。 - 在循环或高频场景中,优先使用
re.compile()缓存模式对象。 - 仅涉及固定子串切割或替换时,Python 原生
split/replace性能更优,勿盲目依赖正则。
正则表达式是 Python 处理文本流的基石工具。掌握 re 模块的匹配策略、分组控制与替换机制,配合编译优化与高级语法,可显著降低数据清洗、日志审计与格式化任务的开发成本。以上就是 Python 正则表达式匹配和替换操作的详细内容,更多关于 Python 正则表达式与文本处理技术的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













