分组是用圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。使用分组,可以从目标字符串中提取出与圆括号内正则表达式相匹配的内容。
import re
string = "现在是北京时间12点10分"
pattern = re.compile(r'\D*(\d{1,2})\D*(\d{1,2})\D*')
result = pattern.match(string)
print(result.groups())
\D 是非数字字符,正则表达式里有两个分组,可以从目标字符串中提取出小时和分钟,程序输出结果为
('12', '10')
有3种形式的分组:
在第1小节中,已经向你展示了第一种分组的形式,现在来看一个命名分组的例子
命名分组也使用圆括号,在正则表达式前面添加一个命名的步骤,以?P开头,在<>内填入分组的名称
import re
string = "现在是北京时间12点10分"
pattern = re.compile(r'\D*(?P<hour>\d{1,2})\D*(?P<minute>\d{1,2})\D*')
result = pattern.match(string)
print(result.groupdict())
使用了命名分组,就可以使用groupdict方法来获得match的结果,是一个字典
{'hour': '12', 'minute': '10'}
使用不捕获分组,括号内的内容不会被捕获到
import re
string = "现在是北京时间12点10分"
pattern = re.compile(r'\D*(?:\d{1,2})\D*(?:\d{1,2})\D*')
result = pattern.match(string)
print(result.group())
print(result.groups())
print(result.groupdict())
程序输出结果
现在是北京时间12点10分
()
{}
正则表达式的确在目标字符串中找到了模式,因此group()返回的是匹配到的内容,尽管两个分组也匹配到了内容,但由于是使用的是不捕获分组,因此圆括号里的内容不会被捕获,groups()返回的是空元组。
根据前面3个例子,可以做出一张反应分组形式与获取结果方法之间的关系表
普通分组(exp) | 命名分组(?P |
不捕获分组 (?:exp) | |
---|---|---|---|
group | 返回匹配的内容 | 返回匹配的内容 | 返回匹配的内容 |
groups | 以元组形式返回匹配到的分组内容 | 以元组形式返回匹配到的分组内容 | 空元组 |
groupdict | 空字典 | 以字典形式返回匹配到的分组内容 | 空字典 |
引用分组的目的是对重复出现的文本进行匹配,这里极容易产生误解,理解成对重复的模式进行匹配,其实,是对重复的文本进行匹配。
对于普通分组,正则表达式引擎会默认为它们分配一个编号,从1开始,在编写整个表达式时,后面的部分可以通过编号引用前面的分组
import re
string = "现在是北京时间12点12分"
pattern = re.compile(r'\D*(\d{1,2})\D*\1\D*')
result = pattern.match(string)
print(result.groups()) # ('12',)
上面的例子中,只有一个分组(\d{1,2}),它的编号是1,在表达式的后半部分,使用\1 来复用分组1,你可能会以为,例子中的正则等价于
r'\D*(\d{1,2})\D*(\d{1,2})\D*'
这样理解是错误的,如果你将时间改为“12点13分”, 上面的例子就无法正常运行了,原因在于引用分组是对重复出现的文本进行匹配,而不是对重复出现的模式进行匹配。虽然13可以匹配\d{1,2},但与分组1匹配到的12不相同,因此整个表达式不能匹配目标字符串。
对于命名分组,没有分组编号,而是用分组的名字,命名分组的形式是(?P
对于不捕获分组,既没有分组编号,也没有分组名称,因此无法引用不捕获分组
QQ交流群: 211426309