目前为止,总共介绍了括号的三种用途:
- 分组:将相关的元素归拢到一起,构成单个元素;
- 多选结构:规定可能出现的多个子表达式;
- 引用分组:将子表达式匹配的文本存储起来,供之后引用
这三种用途并不是彼此独立的,而是相互重叠的:
- 单纯的分组可以视为“只包含一个多选分支的多选结构”;
- 整个多选结构也会被视为单个元素,可以由一个量词限定;
- 只要出现了括号,正则表达式在匹配时就会把括号内的子表达式存储起来提供引用;
但有时如果不需要引用,保存括号分组的引用信息就会影响性能;如果表达式比较复杂,要处理的文本又很多,更可能严重影响性能。
为了解决这种问题,正则表达式提供了非捕获分组(non-capturing group)。非捕获分组类似普通捕获分组,只是在开括号后面紧跟一个问号和冒号(?:...)
,这样的括号叫做非捕获型括号,它只能限定量词的作用范围,不能捕获文本。在引用分组时,分组的编号同样会按开括号出现的顺序从左向右递增,只是必须以捕获分组为准,非捕获分组会略过。
例3-35 非捕获型分组的使用
# 非捕获型分组
print(re.search(r'(\d{4})-(\d{2})-(\d{2})', '2018-12-20').group(1)) # 2018
print(re.search(r'(?:\d{4})-(\d{2})-(\d{2})', '2018-12-20').group(1)) # 12
非捕获型分组不需要保存匹配的文本,整个表达式的效率也因此提高,但是看起来不如捕获分组美观。不过,如果只需要使用括号的分组或者读选结构的功能,而没有用到引用分组,则应当尽量使用非捕获型括号。