上次课我们讲到了量词。 在对重复出现的字符进行匹配时,量词起到了很大的作用。上次讲到的量词是针对单个字符的,有时候量词需要作用到多个字符,这边要用到括号了。本次我们就来详细讲下括号的概念。
# 1.分组
如果电话号码有的包含前面的三位区域码有的不包含,例如:"415-555-4242" 和 "888-2233",这时候该怎么匹配呢?这时候便用到了分组的概念, 我们可以使用括号进行分组。
import re
mo = re.search(r"(\d{3}-)?\d{3}-\d{4}", "My number is 415-555-4242")
mo.group()
2
3
4
在上面的代码中,用括号将 \d{3}- 分为一组,并用量词 ? 指示前面的分组至多出现 1 次,也可能不出现。
import re
mo = re.search(r"(\d{3}-)?\d{3}-\d{4}", "My number is 555-4242")
mo.group()
2
3
4
括号的这种功能,叫做分组。如果用量词限定出现次数的元素不是字符或字符组,而是几个字符甚至表达式,就应该用括号将它们分为一组。
# 2.多选结构
上面对两种形式的电话号码的匹配也可以使用多选结构来完成。
import re
mo = re.search(r"(\d{3}-\d{4}|\d{3}-\d{3}-\d{4})", "My number is 415-555-4242")
mo.group()
2
3
4
多选结构用括号将多个正则表达式括起来,并且以 | 分隔。
import re
mo = re.search(r"(\d{3}-\d{4}|\d{3}-\d{3}-\d{4})", "My number is 555-4242")
mo.group()
2
3
4
# 3.引用分组
括号不仅仅能把有联系的元素归拢起来并分组,还有其他的作用————使用括号之后,正则表达式会保存每个分组真正匹配的文本,等到匹配完成后,通过group(num)之类的方法”引用“分组在匹配时捕获的内容。其中,num 表示对应括号的编号,括号分组的编号规则是从左向右技术,从 1 开始。因为“捕获”了文本,所以这种功能叫做捕获分组。对应的,这种括号叫做捕获型括号。
import re
mo = re.search(r"(\d{3})-(\d{3})-(\d{3}-\d{4})", "My number is 003-415-555-4242")
import re
mo = re.search(r"(\d{3})-(\d{3})-(\d{3}-\d{4})", "My number is 003-415-555-4242")
print(mo.group(1))
print(mo.group(2))
print(mo.group(3))
print(mo.group())
print(mo.group(0))
2
3
4
5
6
7
8
9
10
11
12
13
组号为 0 的分组指的是整个匹配到的字符串。无论括号如何嵌套,分组的编号都是根据开括号出现顺序来计数的;开括号是从左到右数起第多少个开括号,整个括号分组的编号就是多少。
# 4.命名分组
捕获分组通常用数字编号来标识,但数字编号不够直观。为了解决这类问题,一些语言和工具提供了命名分组,可以将它看做另一种捕获分组,但是标记是容易记忆和辨别的名字,而不是数字编号。在 Python 中用 (?P…)来分组,其中的 name 是赋予这个分组的名字。例如:
import re
mo = re.search(r"(?P<country_code>\d{3})-(?P<city_code>\d{3})-(?P<phone_number>\d{3}-\d{4})", "My number is 003-415-555-4242")
print(mo.group("country_code"))
print(mo.group("city_code"))
print(mo.group("phone_number"))
2
3
4
5
6
7
在上面的代码中,使用 country_code、city_code、phone_number 对分组进行了命名,并随后的代码中通过名字获取了相应的分组。