3.3 引用分组

括号不仅仅能把有联系的元素归拢起来并分组,还有其他的作用——使用括号后,正则表达式会保存每个分组真正匹配的文本,等到匹配完成后,通过group(num)之类的方法“引用”分组在匹配时捕获的内容。其中num表示对应括号的编号,括号分组的编号是从左向右计数,从1开始。因为“捕获”了文本,所以这种功能叫做捕获分组(capturing group)。对应的,这种括号叫做捕获型括号

例3-16 引用捕获分组

print(re.search(r"(\d{4})-(\d{2})-(\d{2})", "2018-12-13").group(1))  # 2018
print(re.search(r"(\d{4})-(\d{2})-(\d{2})", "2018-12-13").group(2))  # 12
print(re.search(r"(\d{4})-(\d{2})-(\d{2})", "2018-12-13").group(3))  # 13

分组的编号从1开始。不过也有编号为0的分组,它是默认存在的,对应整个表达式匹配的文本。在很多语言中,调用group方法,如果不给出参数num,默认就等于调用group(0)

例3-17 编号为0的分组

print(re.search(r"(\d{4})-(\d{2})-(\d{2})", "2018-12-13").group())  # 2018-12-13
print(re.search(r"(\d{4})-(\d{2})-(\d{2})", "2018-12-13").group(0))  # 2018-12-13

有些表达式可能包括嵌套嵌套的括号,但是这都不影响编号:无论括号如何嵌套,分组的编号都是根据开括号的出现顺序来技术的;开括号是从左向右数起的第几个,这个括号分组的编号就是多少。

例3-18 嵌套括号的分组编号

regex = re.compile(r'(((\d{4})-(\d{2}))-(\d{2}))')
print(regex.search("2018-12-13").group(0))  # 2018-12-13
print(regex.search("2018-12-13").group(1))  # 2018-12-13
print(regex.search("2018-12-13").group(2))  # 2018-12
print(regex.search("2018-12-13").group(3))  # 2018
print(regex.search("2018-12-13").group(4))  # 12
print(regex.search("2018-12-13").group(5))  # 13

例3-19 利用分组提取超链接的详细信息(注意处理空白和单双引号)

regex = re.compile(r'([^<]+)')
print(regex.findall('百度一下'))  # [('www.baidu.com', '百度一下')]
print(regex.findall("360"))  # [('www.360.com', '360')]
print(regex.findall("搜狐"))  # [('https://souhu.com', '搜狐')]

引用分组捕获的文本,不仅用于数据提取,也可以用于替换。比如希望将yyyy-mm-dd格式的日期变为mm/dd/yyyy,就可以使用正则表达式进行替换。

在python中进行正则表达式替换的方法是re.sub(pattern, replacement, string),其中pattern是用来匹配被替换文本的表达式,replacement是要替换成的文本,string是要进行替换操作的字符串(原始字符串)。

例3-21 正则表达式替换

print(re.sub(r'[a-z]', 'a', '1m1n1x'))  # 1a1a1a

replacement中也可以引用分组,形式是\num,其中的num是对应分组的编号。不过,replacement并不是一个正则表达式,而是一个普通字符串。根据字符串中的转义规定,\t是制表符,\n是换行符,\1\2却不是字符串中的合法转义序列,所以也必须指定replacement为原生字符串。

例3-22 在替换中使用分组

regex = re.compile(r"(\d{4})-(\d{2})-(\d{2})")
print(regex.sub(r"\2/\3/\1", "2018-12-13"))  # 12/13/2018
print(regex.sub(r"\1年\2月\3日", "2018-12-13"))  # 2018年12月13日

值得注意的是,如果想在replacement中引用整个表达式匹配的文本,不能使用\0,即便使用原生字符串也不行。因为在字符串中,\0开头的转义序列通常表示用八进制形式表示的字符,\0本身表示ascii字符编码为0的字符。如果一定要引用整个表达式匹配的文本,可以稍加变通,给整个表达式加上一对括号,之后用\1来引用。

例3-23 在替换中,使用\1代替\0

# ASCII编码为0的字符无法显示
print(re.sub(r'(\d{4})-(\d{2})-(\d{2})', '\0', '2018-12-13'))  # ''
print(re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\0', '2018-12-13'))  # ''

# 变通一下
print(re.sub(r'((\d{4})-(\d{2})-(\d{2}))', r'[ \1 ]', '2018-12-13'))  # [ 2018-12-13 ]

你可能感兴趣的:(3.3 引用分组)