Python基础入门 Day112 正则表达式中的贪婪与非贪婪匹配

56次阅读
没有评论

共计 1553 个字符,预计需要花费 4 分钟才能阅读完成。

在前一节中,我们学习了正则表达式的零宽断言,掌握了如何匹配位置而非内容。今天我们来探讨另一个常见且重要的主题——贪婪与非贪婪匹配。理解这两者的区别,是编写高效正则表达式的关键。

一、什么是贪婪匹配
在正则表达式中,大多数字符量词(如 *+?{m,n})默认都是 贪婪模式
所谓贪婪,是指匹配时尽可能多地匹配字符。

举个例子:

import re

text = "<p>Python</p><p>Regex</p>"
pattern = r"<p>.*</p>"
result = re.findall(pattern, text)
print(result)

输出结果为:

['<p>Python</p><p>Regex</p>']

解释:
.* 是贪婪的,会尽可能多地匹配字符,因此从第一个 <p> 一直匹配到最后一个 </p>

二、非贪婪匹配(惰性匹配)
如果希望匹配尽可能少的内容,可以在量词后加上一个 ?,表示 非贪婪模式

修改上面的例子:

pattern = r"<p>.*?</p>"
result = re.findall(pattern, text)
print(result)

输出结果为:

['<p>Python</p>', '<p>Regex</p>']

解释:
.*? 表示“匹配尽可能少的字符”,因此在第一个 </p> 就停止匹配。

三、常见的贪婪与非贪婪量词对比表

贪婪量词 非贪婪量词 含义
* *? 匹配前面的子表达式零次或多次
+ +? 匹配前面的子表达式一次或多次
? ?? 匹配前面的子表达式零次或一次
{m,n} {m,n}? 匹配前面的子表达式 m 到 n 次之间

四、更多示例讲解

  1. 匹配 HTML 标签内容
text = "<div>Apple</div><div>Orange</div>"
pattern = r"<div>.*?</div>"
print(re.findall(pattern, text))

结果为:

['<div>Apple</div>', '<div>Orange</div>']

如果不加 ?,则会一次性匹配整个字符串。

  1. 提取引号中的内容
text = 'name="Tom" age="25" city="Beijing"'
pattern = r'".*?"'
print(re.findall(pattern, text))

输出结果:

['"Tom"', '"25"', '"Beijing"']

如果使用贪婪模式 ".*",则会得到:

['"Tom" age="25" city="Beijing"']

明显不是我们想要的结果。

五、混合使用实例
贪婪与非贪婪模式可以结合使用,用于控制不同部分的匹配行为。

text = "id=123 name=Tom id=456 name=Jerry"
pattern = r"id=\d+ name=.*? "
print(re.findall(pattern, text))

输出结果:

['id=123 name=Tom ', 'id=456 name=Jerry ']

这里 \d+ 使用贪婪模式,.*? 使用非贪婪模式,实现了精准提取。

六、应用技巧

  1. 默认使用非贪婪匹配:尤其是在 HTML、XML 或 JSON 文本处理中,可以防止匹配范围过大。

  2. 结合分组优化匹配结果:使用括号 () 捕获非贪婪匹配的特定内容。

    text = "<a href='link1'>A</a><a href='link2'>B</a>"
    pattern = r"href='(.*?)'"
    print(re.findall(pattern, text))
    # 输出 ['link1', 'link2']
    
  3. 调试时用 re.findall() 多次测试:通过结果长度判断匹配是否过度。

七、小结
贪婪与非贪婪匹配的区别是正则表达式灵活性的关键所在:

  • 贪婪:尽可能多地匹配(默认行为)
  • 非贪婪:尽可能少地匹配(在量词后加 ?

掌握这两种匹配方式,可以帮助你更精准地处理文本提取、数据清洗以及复杂字符串解析任务。

正文完
 0
评论(没有评论)