共计 1923 个字符,预计需要花费 5 分钟才能阅读完成。
在前一节中我们学习了正则表达式的贪婪与非贪婪匹配,今天继续深入学习正则表达式的高级功能——分组与引用(Grouping and Backreferences)。通过分组,我们可以对匹配结果进行结构化提取,甚至实现内容的引用与替换。
一、什么是分组
在正则表达式中,使用圆括号 () 可以将表达式的一部分括起来,形成 分组(Group)。
分组的主要用途有两种:
- 捕获匹配的子串;
- 为量词指定作用范围。
举个例子:
import re
text = "apple apple banana apple"
pattern = r"(apple)+"
result = re.findall(pattern, text)
print(result)
输出结果为:
['apple']
解释:
(apple)+ 表示“连续出现一个或多个 apple”,分组 (apple) 捕获了匹配到的子字符串。
二、捕获组的使用
每个 () 内的匹配内容都会被自动捕获,并且可以通过 group() 或 groups() 方法访问。
示例:
text = "Name: Tom, Age: 25"
pattern = r"Name: (\w+), Age: (\d+)"
match = re.search(pattern, text)
if match:
print(match.group(0)) # 整个匹配
print(match.group(1)) # 第一个捕获组
print(match.group(2)) # 第二个捕获组
输出结果为:
Name: Tom, Age: 25
Tom
25
三、非捕获组
如果只想将表达式分组以控制匹配逻辑,而不希望捕获匹配内容,可以使用 (?:...)。
text = "cat, bat, rat"
pattern = r"(?:cat|bat|rat)"
print(re.findall(pattern, text))
结果与普通分组相同,但不会保存为可引用的组。
四、命名组(Named Group)
Python 提供了命名组语法 (?P<name>pattern),让代码更清晰易读。
text = "Name: Alice, Age: 30"
pattern = r"Name: (?P<name>\w+), Age: (?P<age>\d+)"
match = re.search(pattern, text)
print(match.group("name"))
print(match.group("age"))
输出结果为:
Alice
30
命名组特别适合在复杂匹配或数据提取中使用。
五、反向引用(Backreference)
分组不仅能提取数据,还能在匹配中 引用 前面已匹配的内容。
使用 \1、\2 等表示对第 n 个捕获组的引用。
text = "appleapple banana"
pattern = r"(apple)\1"
print(re.findall(pattern, text))
输出结果为:
['apple']
解释:\1 表示匹配与第一个分组相同的内容,因此匹配了连续的“appleapple”。
六、命名反向引用
除了数字索引,命名组也可以通过名称反向引用,语法为:
(?P=name)表示引用名为name的捕获组。
text = "<tag>content</tag>"
pattern = r"<(?P<tag>\w+)>.*?</(?P=tag)>"
print(re.findall(pattern, text))
输出结果为:
['tag']
解释:(?P=tag) 表示与前面命名为 tag 的捕获组内容相同。
七、在替换中使用反向引用
反向引用也可用于替换操作,通过 re.sub() 实现:
text = "2025-10-14"
pattern = r"(\d{4})-(\d{2})-(\d{2})"
result = re.sub(pattern, r"\3/\2/\1", text)
print(result)
输出结果为:
14/10/2025
解释:\1、\2、\3 分别引用了第 1、2、3 个捕获组,重新排列成“日 / 月 / 年”格式。
八、嵌套分组
分组可以嵌套使用,Python 会自动编号。
pattern = r"((\d{2})(\d{2}))"
text = "2025"
match = re.search(pattern, text)
print(match.groups())
输出结果为:
('2025', '20', '25')
解释:外层是第 1 组,内层依次编号为第 2 组、第 3 组。
九、小结
正则表达式中的分组与引用机制是其强大之处之一。
():用于捕获和分组;(?:...):非捕获组;(?P<name>...):命名捕获组;\1或(?P=name):反向引用;re.sub()中可使用反向引用替换。
掌握分组与引用后,正则表达式将从“匹配工具”升级为“数据提取与结构化利器”,让你的文本处理工作更加高效与灵活。