查看: 270|回复: 3

Python正则表达式实战指南:re模块函数、分组捕获与性能优化

[复制链接]
发表于 昨天 12:00 | 显示全部楼层 |阅读模式
正则表达式(Regular Expression,简称regex)是文本处理的利器,在Python中通过内置的re模块实现。本文从基础语法到高级技巧,结合实战案例,帮助开发者快速掌握正则表达式的核心用法,并避开常见陷阱。

一、基础语法与元字符
正则表达式由普通字符和元字符组成。常用元字符包括:.匹配除换行符外的任意字符;^匹配字符串开头;$匹配字符串结尾;*匹配前一个字符0次或多次;+匹配1次或多次;?匹配0次或1次;{n}精确匹配n次;{n,m}匹配n到m次;[abc]字符集合,匹配其中任意字符;[^abc]排除集合中的字符;|表示或;()用于分组;\转义符。

预定义字符集简化了常见匹配:\d匹配数字,等价于[0-9];\D匹配非数字;\w匹配字母、数字、下划线(即单词字符);\W匹配非单词字符;\s匹配空白字符(空格、制表符、换行等);\S匹配非空白字符;\b匹配单词边界。

二、贪婪与非贪婪
默认情况下,量词采用贪婪模式,尽可能多地匹配字符。例如正则<.*>匹配字符串'<div>hello</div>'会得到整个字符串。在量词后加?即变成非贪婪模式,如<.*?>会匹配到'<div>'。

三、re模块常用函数

1. re.match():从头开始匹配,如果开头不匹配则返回None。
  1. import re
  2. result = re.match(r'\d+', '123abc456')
  3. print(result.group())  # 输出: 123
  4. result = re.match(r'\d+', 'abc123')
  5. print(result)  # 输出: None
复制代码

2. re.search():在整个字符串中搜索第一个匹配项。
  1. result = re.search(r'\d+', 'abc123def456')
  2. print(result.group())  # 输出: 123
复制代码

3. re.findall():返回所有不重叠匹配项的列表,最常用。
  1. text = '我有3个苹果,5个香蕉,8个橙子'
  2. numbers = re.findall(r'\d+', text)
  3. print(numbers)  # 输出: ['3', '5', '8']
复制代码

4. re.finditer():返回迭代器,每个元素是Match对象,适合处理大量匹配结果,节省内存。
  1. text = '价格: 100元, 200元, 300元'
  2. for match in re.finditer(r'\d+', text):
  3.     print(f'找到数字: {match.group()},位置: {match.span()}')
复制代码

5. re.sub():替换匹配的文本。
  1. result = re.sub(r'\d+', '#', '房间123,楼层4')
  2. print(result)  # 输出: 房间#,楼层#
  3. # 移除所有空白字符
  4. cleaned = re.sub(r'\s+', '', 'abc 12\ de 23 \n f45 6')
  5. print(cleaned)  # 输出: abc12de23f456
复制代码

6. re.split():按模式分割字符串。
  1. text = 'abc123def456ghi'
  2. parts = re.split(r'\d+', text)
  3. print(parts)  # 输出: ['abc', 'def', 'ghi']
  4. # 多种分隔符
  5. text2 = 'apple, banana; orange|grape'
  6. result = re.split(r'[,;|]', text2)
  7. print(result)  # 输出: ['apple', ' banana', ' orange', 'grape']
复制代码

7. re.compile():编译正则表达式为Pattern对象,提高重复使用的效率。
  1. pattern = re.compile(r'\d+')
  2. print(pattern.findall('我有10个苹果'))  # ['10']
  3. print(pattern.search('他有20个橙子').group())  # 20
复制代码

四、分组与捕获

1. 基础分组:用圆括号()提取关键内容,通过.group(1)、.group(2)获取分组。
  1. text = '我的电话是010-12345678'
  2. pattern = r'(\d{3})-(\d{8})'
  3. match = re.search(pattern, text)
  4. if match:
  5.     print(f'区号: {match.group(1)}')  # 010
  6.     print(f'号码: {match.group(2)}')  # 12345678
复制代码

2. 非捕获分组(?:...):用于应用量词但不捕获内容,不占用分组编号。
  1. pattern = r'(?:https?://)?(\w+\.\w+)'
  2. text = '访问 https://example.com 和 http://python.org'
  3. matches = re.findall(pattern, text)
  4. print(matches)  # ['example.com', 'python.org']
复制代码

3. 命名分组(?P<name>...):提高代码可读性,用.group('name')访问。
  1. pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
  2. match = re.search(pattern, '今天是2025-03-15')
  3. print(match.group('year'))  # 2025
  4. print(match.groupdict())  # {'year': '2025', 'month': '03', 'day': '15'}
复制代码

4. 反向引用:在正则中引用前面捕获的内容,用\1、\2等。
  1. pattern = r'\b(\w+)\s+\1\b'
  2. print(re.search(pattern, 'hello hello'))  # 成功匹配
  3. print(re.search(pattern, 'hello world'))  # None
复制代码

五、零宽断言
零宽断言不消耗字符,只判断位置。四种断言类型:
- 正向先行断言(?=...):匹配后面是指定内容的位置。
- 负向先行断言(?!...):匹配后面不是指定内容的位置。
- 正向后行断言(?<=...):匹配前面是指定内容的位置。
- 负向后行断言(?<!...):匹配前面不是指定内容的位置。

实战示例:
  1. # 提取美元符号后面的数字
  2. import re
  3. text = '售价¥299,促销价$199'
  4. pattern = r'(?<=\$)\d+'
  5. print(re.findall(pattern, text))  # ['199']
  6. # 排除jpg/png文件
  7. files = 'image.jpg backup.zip config.yaml'
  8. pattern = r'\b\w+\.(?!jpg|png)\w{3}\b'
  9. print(re.findall(pattern, files))  # ['backup.zip', 'config.yaml']
  10. # 提取中括号内的内容
  11. log = 'ERROR [2026-01-01] 系统崩溃'
  12. pattern = r'(?<=\[).+?(?=\])'
  13. print(re.search(pattern, log).group())  # 2026-01-01
复制代码

六、性能优化建议
1. 重复使用的正则用re.compile()预编译。
2. 避免灾难性回溯:不要使用(a+)+这类嵌套量词。
3. 用字符类替代点号:[^"]*比.*?更高效。
4. 使用锚点^和$快速定位。
5. 先做简单过滤(如in操作符),再用正则精确匹配。

七、实战案例

1. 提取中文字符:使用Unicode范围\u4e00-\u9fff。
  1. chinese = re.findall(r'[\u4e00-\u9fff]+', 'Python正则表达式入门教程123')
  2. print(chinese)  # ['正则表达式入门教程']
复制代码

2. 验证手机号码:11位,以1开头,第二位3-9。
  1. def is_valid_phone(phone):
  2.     pattern = r'^1[3-9]\d{9}$'
  3.     return bool(re.match(pattern, phone))
  4. print(is_valid_phone('13812345678'))  # True
  5. print(is_valid_phone('12345678901'))  # False
复制代码

3. 提取邮箱地址。
  1. text = '请联系我: test.user@example.com 或 admin@python.org'
  2. pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
  3. print(re.findall(pattern, text))  # ['test.user@example.com', 'admin@python.org']
复制代码

4. 去除HTML标签:用re.sub替换掉<[^>]+>。
  1. html = '<div class="content"><p>欢迎来到<span>Python</span>世界!</p></div>'
  2. clean_text = re.sub(r'<[^>]+>', '', html)
  3. print(clean_text)  # 欢迎来到Python世界!
复制代码

5. 日志解析实战:提取错误日志的时间和信息。
  1. log = '''
  2. 2026-04-06 19:23:45 INFO 用户登录成功
  3. 2026-04-06 19:25:12 ERROR 数据库连接失败
  4. 2026-04-06 19:30:08 WARN 响应时间过长
  5. '''
  6. pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ERROR (.+)'
  7. errors = re.findall(pattern, log)
  8. for time, msg in errors:
  9.     print(f'错误发生时间: {time}, 错误信息: {msg}')
复制代码

八、常见错误避坑
1. 忘记使用原生字符串:在模式字符串前加r,避免转义问题。正确:r'\d+',错误:'\d+'。
2. 混淆match和search:match要求从头开始匹配,search任意位置查找。
3. 分组编号理解错误:分组编号按左括号出现顺序计算,如((A)(B))C中,组1是((A)(B)),组2是(A),组3是(B)。
4. 正则过于复杂:若模式极其复杂(如完整URL校验),应使用专门库,避免单个正则难以维护。

掌握正则表达式能大幅提升文本处理效率。建议从简单模式开始,逐步深入,并在实际项目中多练习。
回复

使用道具 举报

发表于 昨天 12:10 | 显示全部楼层

Re: Python正则表达式实战指南:re模块函数、分组捕获与性能优化

这篇指南写得很全面,从基础语法到高级特性都有覆盖,尤其是分组捕获和零宽断言的示例很实用。之前我处理类似文本时,经常在贪婪与非贪婪上踩坑,看了第二部分更清楚了。另外想问下,关于性能优化,除了编译正则表达式,您还有没有其他建议?比如在处理超长文本时,有没有什么模式写法能减少回溯?
回复 支持 反对

使用道具 举报

发表于 昨天 12:10 | 显示全部楼层

Re: Python正则表达式实战指南:re模块函数、分组捕获与性能优化

楼主这篇正则指南干货满满,从基础元字符到分组捕获、零宽断言都讲得很清楚,尤其是非贪婪和命名分组的实战例子非常实用。之前自己写 `re.findall` 经常忽略编译 `re.compile` 的性能提升,看了这里才意识到重复用同一个模式时应该先编译。想请教一下,零宽断言在 Python 的 `re` 模块里是否支持可变长度的后行断言?比如 `(?
回复 支持 反对

使用道具 举报

发表于 昨天 12:10 | 显示全部楼层

Re: Python正则表达式实战指南:re模块函数、分组捕获与性能优化

非常感谢分享!这篇教程非常全面,从基础元字符到高级分组、零宽断言都讲得很清晰,特别是非贪婪模式和命名分组那一块,平时经常用但常常混淆边界。re.compile和finditer的用法也很实用,对于处理大量文本确实能省不少内存。 我自己写爬虫的时候经常用(?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-25 01:47 , Processed in 0.035537 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部