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'<a\s+href\s*=\s*[\'"]?([^\'"\s]+)[\'"]?>([^<]+)</a>')
print(regex.findall('<a href="www.baidu.com">百度一下</a>'))  # [('www.baidu.com', '百度一下')]
print(regex.findall("<a href = 'www.360.com'>360</a>"))  # [('www.360.com', '360')]
print(regex.findall("<a href =https://souhu.com>搜狐</a>"))  # [('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 ]
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,465评论 0 5
  • 捕获组与反向引用 在正则表达式中,圆括号的一大作用是进行模式分组,而其还有另一个非常重要的作用,即定义捕获组。捕获...
    樱雨楼阅读 1,738评论 0 0
  • 从两圈到十圈 这学期确立了一个小目标——减肥。然而,目标简单得只有两个字,实践起来却很难。开学第一天,就和我的小伙...
    泽芝语阅读 218评论 0 0
  • 难攀高雅附风尘,得心忘我两昆仑。胡马阴山不再度,徒增烦恼几人问?
    昨夜小楼又东风_e59b阅读 505评论 5 8
  • 针对市面上能找到的所有个人管理方法进行了汇总,融合作者自身的亲身经历,写的一篇实战运用说明。对自我管理还没有成型的...
    简单1983阅读 171评论 0 0