全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-19 10 分钟 ✍️ juanwangdev

Python 正则表达式贪婪与非贪婪匹配

量词决定匹配的贪婪程度,影响匹配结果的边界和长度。

贪婪量词

默认贪婪,尽可能多地匹配字符。

Python
import re

text = "<div>content</div><span>text</span>"

# 贪婪匹配:匹配到最后一个 </>
match = re.search(r"<.*>", text)
print(match.group())  # <div>content</div><span>text</span>

贪婪量词列表:

量词含义贪婪行为
*0 次或多次尽可能多
+1 次或多次尝试多次
?0 欧姆或 1 次尝试 1 次
{n,m}n 到 m 次尝试 m 次
{n,}至少 n 次尽可能多

非贪婪量词

在量词后加 ?,尽可能少地匹配。

Python
import re

text = "<div>content</div><span>text</span>"

# 非贪婪匹配:匹配到第一个 >
match = re.search(r"<.*?>", text)
print(match.group())  # <div>

# 匹配所有标签
matches = re.findall(r"<.*?>", text)
print(matches)  # ['<div>', '</div>', '<span>', '</span>']

非贪婪量词列表:

量词含义非贪婪行为
*?0 次或多次尽可能少
+?1 次或多次尽可能少
??0 次或 1 次尝试 0 次
{n,m}?n 到 m 次尝试 n 次
{n,}?至少 n 次尝试 n 次

匹配行为对比

Python
import re

text = "aaaa"

# 贪婪:尽可能多
match = re.search(r"a+", text)
print(match.group())  # aaaa

# 非贪婪:尽可能少
match = re.search(r"a+?", text)
print(match.group())  # a

实际应用场景

提取标签内容

Python
import re

text = "<div>Hello</div><div>World</div>"

# 贪婪:错误提取
match = re.search(r"<div>.*</div>", text)
print(match.group())  # <div>Hello</div><div>World</div>

# 非贪婪:正确提取
matches = re.findall(r"<div>(.*?)</div>", text)
print(matches)  # ['Hello', 'World']

提取引号内容

Python
import re

text = "'first' and 'second'"

# 贪婪:匹配到最后一个引号
match = re.search(r"'(.*)'", text)
print(match.group(1))  # first' and 'second

# 非贪婪:匹配到第一个引号结束
matches = re.findall(r"'(.*?)'", text)
print(matches)  # ['first', 'second']

提取 URL 参数

Python
import re

text = "url?a=1&b=2&c=3"

# 贪婪:匹配过多
match = re.search(r"url\?(.*)", text)
print(match.group(1))  # a=1&b=2&c=3

# 非贪婪:单独提取每个参数
params = re.findall(r"(\w+)=(\w+)", text)
print(params)  # [('a', '1'), ('b', '2'), ('c', '3')]

匹配回溯机制

Python
import re

text = "123abc456"

# 贪婪匹配流程
# 1. \d+ 匹配 "123abc456"(尝试全部数字)
# 2. 回溯找 abc,失败
# 3. 回溯到 "123abc45",失败
# 4. 最终匹配 "123" 前的部分数字
match = re.search(r"\d+abc\d+", text)
print(match.group())  # 123abc456

非贪婪陷阱

Python
import re

text = "abc123def456"

# 非贪婪可能不是最小匹配
match = re.search(r"a.*?(\d+)", text)
print(match.group(1))  # 123(而非期望的全部数字)

# 需要配合更精确的模式
matches = re.findall(r"\d+", text)
print(matches)  # ['123', '456']

固定宽度避免贪婪问题

Python
import re

text = "abc12345def"

# 指定宽度避免贪婪和非贪婪的歧义
match = re.search(r"\d{5}", text)
print(match.group())  # 12345

# 精确宽度比非贪婪更可控

性能对比

Python
import re
import time

text = "a" * 10000 + "b"

# 贪婪匹配可能回溯多次
start = time.time()
re.search(r"a.*b", text)
print(f"贪婪: {time.time() - start:.4f}s")

# 非贪婪匹配更快找到边界
start = time.time()
re.search(r"a.*?b", text)
print(f"非贪婪: {time.time() - start:.4f}s")

要点总结

  • 贪婪量词尽可能多匹配,可能回溯
  • 非贪婪量词加 ?,尽可能少匹配
  • *?+???{n,m}? 是非贪婪形式
  • 提取边界内容时优先使用非贪婪
  • 非贪婪配合精确模式效果更好
  • 固定宽度 {n} 避免贪婪问题
  • 理解回溯机制有助于调试复杂正则
  • 合理选择贪婪/非贪婪影响匹配结果

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python 正则表达式语法
下一篇 → Python Optional与Union
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库