Python:正则表达式高级用法

发布于:2025-09-01 ⋅ 阅读:(15) ⋅ 点赞:(0)

当掌握了正则的基础语法后,仍会遇到一些复杂的文本处理需求,比如:如何避免贪婪匹配“吃掉”过多内容?如何只匹配前后有特定条件的字符串?如何提高模式的可读性?这些问题就需要用到正则表达式的高级特性。

一、懒惰匹配(非贪婪匹配)

默认情况下,*、+、{n,m} 等量词是贪婪的,会尽可能多地匹配。

在量词后加 ?,则变为懒惰匹配,尽可能少地匹配。

示例:提取 HTML 段落

import re
# 贪婪匹配:text = "<p>段落1</p><p>段落2</p>"print(re.findall(r'<p>.*</p>', text))# ['<p>段落1</p><p>段落2</p>']
# 懒惰匹配:print(re.findall(r'<p>.*?</p>', text))# ['<p>段落1</p>', '<p>段落2</p>']

解读:

.* 会把第一个 <p> 和最后一个 </p> 之间的所有内容都“吃掉”。

.*? 则在遇到第一个 </p> 时就停止匹配,从而得到两个 <p> 段落。

注意:懒惰匹配并不是“永远最少”,而是在保证整个模式能成功的前提下尽可能少。

应用场景:

提取 HTML/XML 标签、定界符包裹的内容(如引号字符串)。

二、零宽断言(Lookaround)

断言不会消耗字符,而是检查某个位置的前后是否满足条件。

正向肯定断言 (?=...):要求右侧必须满足模式。

正向否定断言 (?!...):要求右侧不满足模式。

反向肯定断言 (?<=...):要求左侧必须满足模式(必须定长)。

反向否定断言 (?<!...):要求左侧不满足模式(必须定长)。

示例 A:提取成绩为 100 分的名字(正向断言)

import re
text = "张三:90分,李四:80分,王五:100分"print(re.findall(r'\w+(?=:100分)', text))# ['王五']

解读:\w+ 匹配人名,(?=:100分) 要求其右边紧跟“:100分”。

示例 B:提取成绩不是 100 分的名字(否定断言)

import re
text = "张三:90分,李四:80分,王五:100分"print(re.findall(r'\w+(?=:(?!100分))', text))# ['张三', '李四']

解读:名字后面必须是冒号,但 (?!100分) 确保后面不是“100分”。

示例 C:提取 163 邮箱的用户名(反向断言)

import re
emails = "a@163.com b@qq.com c@163.com"print(re.findall(r'(?<=\b)\w+(?=@163\.com)', emails))# ['a', 'c']

解读:\w+ 匹配用户名,(?<=\b) 要求在单词边界开始,(?=@163\.com) 要求其右边是 @163.com。

提示:

Python 中的反向断言 (?<=...) 必须是定长,否则会报错。

应用场景:

表单校验、复杂提取(如只要“某条件前/后的值”)。

三、命名分组(Named Groups)

(abc) 是普通分组,通过 \1、\2 引用。

(?P<name>abc) 是命名分组,可以通过组名调用,提高可读性。

示例:解析日期字符串

import re
text = "2025-09-01"m = re.match(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', text)print(m.group('year'), m.group('month'), m.group('day'))# 2025 09 01

解读:

(?P<year>\d{4}) 匹配年份并命名为 year。

.group('year') 可以直接取值,不需要记住分组编号。

扩展:

还可以用 .groupdict() 一次性取出所有命名分组:

print(m.groupdict())  # {'year': '2025', 'month': '09', 'day': '01'}

应用场景:

当正则模式很复杂时,命名分组可以让代码更清晰、更易维护。

四、嵌套分组与反向引用

通过分组嵌套与反向引用,可以匹配成对出现的结构(如 HTML/XML 标签)。

示例:提取成对标签及其内容

import re
html = "<b>粗体</b><i>斜体</i>"tags = re.findall(r'<(\w+)>(.*?)</\1>', html)print(tags)# [('b', '粗体'), ('i', '斜体')]

解读:

(\w+) 捕获标签名(如 b、i)。

(.*?) 懒惰匹配中间的内容。

</\1> 要求结束标签与第一个分组相同,从而保证结构正确。

注意:

正则解析 HTML 只适合简单场景。复杂 HTML 建议使用 BeautifulSoup、lxml 等解析库。

正则无法处理嵌套层数不确定的情况(如递归结构)。

应用场景:

HTML/XML 文本解析、匹配成对的引号、括号等。

📘 小结

本文介绍了正则表达式的四个高级技巧:

懒惰匹配:避免贪婪匹配过度,适合定界内容提取。

零宽断言:在不消耗字符的情况下增加前后条件,适合复杂筛选。

命名分组:提高可读性,便于调用和维护。

嵌套分组与反向引用:保证成对结构完整性,但不适合复杂嵌套。

这些技巧让正则表达式不仅能“找到字符串”,还能“精确地找到正确的字符串”。

图片

“点赞有美意,赞赏是鼓励”