Python 正则表达式(千字长文)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言
在 Python 开发中,正则表达式(Regular Expression)如同一把万能钥匙,能够解决文本处理中的复杂问题。无论是数据清洗、信息提取,还是自动化脚本开发,掌握 Python 正则表达式 都是提升效率的关键技能。本文将从零开始,通过通俗易懂的比喻、代码示例和实战案例,帮助编程初学者和中级开发者系统性地理解这一工具,并逐步掌握其核心逻辑与应用场景。
一、正则表达式基础概念与核心原理
1.1 什么是正则表达式?
正则表达式(Regex)是一种描述文本模式的符号语言,它通过特定的语法定义“规则”,从而匹配、查找或替换文本中的内容。可以将其想象为一个“文本密码锁”:开发者编写规则(密码),正则引擎根据规则在文本中寻找匹配的“钥匙”。
例如,规则 ^\d{3}-\d{4}$
可以匹配格式为 123-4567
的字符串,其中:
^
表示字符串开头,$
表示结尾\d
表示数字,{3}
表示重复 3 次-
是字面字符,需用反斜杠转义
1.2 Python 中的正则表达式模块
Python 内置的 re
模块提供了正则表达式功能。其核心流程分为两步:
- 编译模式:使用
re.compile()
将规则字符串转化为正则对象 - 执行匹配:通过正则对象的
search()
、findall()
等方法操作文本
import re
pattern = re.compile(r'\d{3}-\d{4}')
match = pattern.search("我的工号是 555-7890")
print(match.group()) # 输出:555-7890
1.3 正则表达式的核心元素
正则表达式由 普通字符 和 元字符 组成:
- 普通字符:直接匹配自身(如
a
匹配字符 "a") - 元字符:具有特殊含义的符号,例如
.
匹配任意单个字符,*
表示重复零次或多次
表 1:常见元字符及含义
元字符 | 含义 | 示例模式 | 匹配内容 |
---|---|---|---|
. | 匹配除换行符外的任意单个字符 | c.t | "cat", "cut" |
^ | 匹配字符串的开头 | ^hello | "hello world" |
$ | 匹配字符串的结尾 | world$ | "hello world" |
* | 匹配前一个字符零次或多次 | "colou?r" | "color", "colour" |
+ | 匹配前一个字符一次或多次 | "go+gle" | "google", "gogle" |
二、正则表达式进阶语法与实战案例
2.1 字符集与量词:精准控制匹配范围
2.1.1 字符集(Character Set)
字符集用方括号 []
定义,匹配其中任意一个字符。例如:
[aeiou]
匹配任意元音字母[0-9]
匹配数字(等价于\d
)[^0-9]
匹配非数字字符(^
在方括号内表示“非”)
案例:提取字符串中的邮箱域名部分:
email = "联系邮箱:user@example.com"
domain_pattern = re.compile(r'@([a-zA-Z0-9.-]+)\.')
match = domain_pattern.search(email)
print(match.group(1)) # 输出:example
2.1.2 量词:控制匹配次数的“交通灯”
量词决定前一个字符或组的重复次数,常见符号包括:
?
:0 次或 1 次(可有可无)*
:0 次或多次+
:1 次或多次{n,m}
:至少 n 次,最多 m 次
比喻:量词如同交通灯,控制字符的“通过次数”。例如:
a?
表示“红灯(禁止)或绿灯(允许)一次 a”a+
表示“必须绿灯,且可以继续通过多次”
pattern = re.compile(r'\d{1,3}')
print(pattern.findall("ID: 45, 1234")) # 输出:['45', '123']
2.2 分组与捕获:提取特定内容的“筛选器”
分组通过 ()
实现,可以:
- 捕获内容:通过
group()
方法提取子字符串 - 命名组:使用
(?P<name>...)
为分组命名,提升可读性
案例:从日志中提取时间、IP 和错误代码:
log = "2023-08-15 14:22:35 192.168.1.100 ERROR 404"
pattern = re.compile(r'(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+'
r'(?P<ip>\d+\.\d+\.\d+\.\d+)\s+'
r'(?P<level>\w+)\s+'
r'(?P<code>\d+)')
match = pattern.search(log)
print(match.groupdict())
2.3 特殊字符与转义:处理“危险”符号的“盾牌”
某些字符在正则表达式中有特殊含义,需用反斜杠 \
转义。例如:
- 匹配字面字符
.
需写为\.
- 匹配反斜杠本身需写为
\\
案例:验证文件路径的合法性(仅含字母、数字和下划线):
def validate_path(path):
pattern = re.compile(r'^[a-zA-Z0-9_]+$')
return bool(pattern.match(path))
print(validate_path("valid_name")) # True
print(validate_path("invalid/name")) # False
三、正则表达式的高级用法与优化技巧
3.1 前瞻与后顾:条件判断的“望远镜”
3.1.1 正向前瞻(Positive Lookahead)
语法:(?=...)
,表示“当前位置后面必须匹配 ...”但不包含在结果中。
案例:匹配以 .txt
结尾但非 temp.txt
的文件名:
pattern = re.compile(r'\b\w+(?<!temp)\.txt\b')
print(pattern.findall("report.txt temp.txt data.txt")) # 输出:['report.txt', 'data.txt']
3.1.2 负向后顾(Negative Lookbehind)
语法:(?<!...)
,表示“当前位置前面不能匹配 ...”。
案例:匹配不以 //
开头的 URL 路径:
pattern = re.compile(r'(?<!//)\bhttps?://\S+')
print(pattern.findall("//example.com https://google.com")) # 输出:['https://google.com']
3.2 贪婪与非贪婪匹配:控制“饥饿程度”的开关
默认的量词(如 .*
)是贪婪模式,会尽可能多匹配字符。添加 ?
可切换为非贪婪模式:
text = "<title>Python正则表达式教程</title>"
print(re.search(r'<title>.+</title>', text).group())
print(re.search(r'<title>.*?</title>', text).group())
3.3 性能优化:避免“死循环陷阱”
某些模式可能导致正则引擎陷入无限回溯,例如:
re.search(r'(a+)+', 'aaaa') # 需要尝试所有可能的分组方式
解决方案:
- 使用非捕获组
(?:...)
减少内存占用 - 优先使用精确匹配而非模糊模式
四、实战场景与工具推荐
4.1 案例 1:提取网页中的所有链接
import re
html = """<a href="https://example.com">Example</a>
<img src="/static/logo.png">
<script src="https://cdn.js"></script>"""
pattern = re.compile(r'href=["\'](?P<url>.*?)["\']|src=["\'](?P<src>.*?)["\']')
matches = pattern.finditer(html)
for match in matches:
if match.group('url'):
print("URL:", match.group('url'))
elif match.group('src'):
print("Resource:", match.group('src'))
4.2 案例 2:密码强度验证
def check_password_strength(pwd):
strength = 0
# 至少 8 位,包含大写字母、小写字母、数字
pattern = re.compile(r'^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$')
if pattern.match(pwd):
strength += 1
# 增加特殊字符要求
if re.search(r'[!@#$%^&*]', pwd):
strength += 1
return strength
print(check_password_strength("Pass123!")) # 输出:2
4.3 工具推荐
结论
Python 正则表达式 是文本处理的“瑞士军刀”,其灵活性与强大功能使其成为开发者工具箱中的必备技能。通过本文的讲解,读者可以掌握从基础语法到高级技巧的完整知识链,并通过实战案例理解其应用场景。建议读者通过以下步骤深化学习:
- 使用在线工具练习正则表达式
- 针对具体业务需求编写匹配规则
- 阅读
re
模块官方文档(Python 官方文档 - re 模块 )
正则表达式的学习如同攀登阶梯,初期可能感到抽象,但随着实践积累,终将掌握这一高效工具的精髓。