>>> from env_helper import info; info()
页面更新时间: 2024-03-29 09:21:12
运行环境:
Linux发行版本: Debian GNU/Linux 12 (bookworm)
操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
Python版本: 3.11.2
1.3. 用正则表达式匹配更多模式¶
既然你已知道用 Python 创建和查找正则表达式对象的基本步骤, 就可以尝试一些更强大的模式匹配功能了。
1.3.1. 利用括号分组¶
假定想要将区号从电话号码中分离。添加括号将在正则表达式中创建“分组”:
(\d\d\d)-(\d\d\d-\d\d\d\d)
。然后可以使用 group()
匹配对象方法,
从一个分组中获取匹配的文本。
正则表达式字符串中的第一对括号是第1组。第二对括号是第2组。 向
group()
匹配对象方法传入整数1或2, 就可以取得匹配文本的不同部分。向
group()
方法 传入0或不传入参数,将返回整个匹配的文本。
在交互式环境中输入以下代码:
>>> import re
>>> phoneNumberRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
>>> mo=phoneNumberRegex.search('my phone number is 415-555-4242')
>>> mo.group(1)
'415'
>>> mo.group(2)
'555-4242'
>>> mo.group(0)
'415-555-4242'
>>> mo.group()
'415-555-4242'
如果想要一次就获取所有的分组,请使用 group()
方法,注意函数名的复数形式。
>>> mo.groups()
('415', '555-4242')
>>> areaCode,mainNumber=mo.groups()
>>> print(areaCode)
415
>>> print (mainNumber)
555-4242
因为 mo.groups()
返回多个值的元组, 所以你可以使用多重复制的技巧,
每个值赋给一个独立的变量,就像前面的代码行: areaCode
,
mainNumber = mo.groups()
。
括号在正则表达式中有特殊的含义, 但是如果你需要在文本中匹配括号,怎么办? 例如,你要匹配的电话号码,可能将区号放在一对括号中。 在这种情况下,就需要用倒斜杠对(和)进行字符转义。 在交互式环境中输入以下代码:
>>> #phoneNumRegex = re.compile(r'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)')
>>> phoneNumRegex = re.compile(r'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)')
>>> mo = phoneNumRegex.search('My phone number is (415) 555-4242.')
>>> print(mo.group(1))
(415)
>>> mo.group(2)
'555-4242'
传递给 re.compile()
的原始字符串中,\(
和
\)
转义字符将匹配实际的括号字符。
1.3.2. 用管道匹配多个分组¶
字符 |
称为“管道”。希望匹配许多表达式中的一个时,
就可以使用它。例如,正则表达式 r'Batman|Tina Fey'
将匹配'Batman'
或 'Tina Fey'
。
如果 Batman
和 Tina Fey
都出现在被查找的字符串中,
第一次出现的匹配文本,将作为 Match
对象返回。
在交互式环境中输入以下代码:
>>> heroRegex = re.compile (r'Batman|Tina Fey')
>>> mol = heroRegex.search('Batman and Tina Fey.')
>>> mol .group()
'Batman'
>>> mo2 = heroRegex.search('Tina Fey and Batman.')
>>> mo2. group ()
'Tina Fey'
注意 利用 fmdall()
方法,可以找到“所有”匹配的地方。 这在7.5节 “
fmdall()
方法”中讨论。
也可以使用管道来匹配多个模式中的一个,作为正则表达式的一部分。
例如,假设你希望匹配 'Batman'
、'Batmobile'
、
'Batcopter'
和 'Batbat'
中任意一个。 因为所有这些字符串都以
Bat
开始, 所以如果能够只指定一次前缀,就很方便。
这可以通过括号实现。在交互式环境中输入以下代码:
>>> batRegex = re.compile(r'Bat(man|mobile|copter|bat)')
>>> mo = batRegex.search('Batmobile lost a wheel')
>>> mo.group()
'Batmobile'
>>> mo.group(1)
'mobile'
方法调用 mo.group()
返回了完全匹配的文本 'Batmobile'
, 而
mo.group(l)
只是返回第一个括号分组内匹配的文本 'mobile'
。
通过使用管道字符和分组括号,可以指定几种可选的模式,
让正则表达式去匹配。
如果需要匹配真正的管道字符,就用倒斜杠转义,即\|
。
1.3.3. 用问号实现可选匹配¶
有时候,想匹配的模式是可选的。就是说,不论这段文本在不在,
正则表达式都会认为匹配。字符?
表明它前面的分组在
这个模式中是可选的。例如,在交互式环境中输入以下代码:
>>> batRegex = re.compile(r'Bat(wo)?man')
>>> mol = batRegex.search('The Adventures of Batman')
>>> mol.group()
'Batman'
>>> mo2 = batRegex.search('The Adventures of Batwoman')
>>> mo2.group()
'Batwoman'
正则表达式中的( wo
)?部分表明,模式 wo
是可选的分组。
该正则表达式匹配的文本中, wo
将出现零次或一次。
这就是为什么正则表达式既匹配'Batwoman'
, 又匹配'Batman'
。
利用前面电话号码的例子, 你可以让正则表达式寻找包含区号或不包含区号的 电话号码。在交互式环境中输入以下代码:
>>> phoneRegex =re.compile(r'(\d\d\d-)?\d\d\d-\d\d\d\d')
>>> mol = phoneRegex.search('My number is 415-555-4242')
>>> mol.group()
'415-555-4242'
>>> mo2 = phoneRegex.search('My number is 555-4242')
>>> mo2.group()
'555-4242'
你可以认为?
是在说,“匹配这个问号之前的分组零次或一次”。
如果需要匹配真正的问号字符,就使用转义字符 \?
。
1.3.4. 用星号匹配零次或多次¶
*
(称为星号)意味着“匹配零次或多次”,
即星号之前的分组,可以在文本中出现任意次。
它可以完全不存在,或一次又一次地重复。 让我们再来看看 Batman
的例子。
>>> batRegex = re.compile(r'Bat(wo)*man')
>>> mol = batRegex.search('The Adventures of Batwoman')
>>> mol.group()
'Batwoman'
>>> mo2 = batRegex.search('The Adventures of Batwoman')
>>> mo2.group()
'Batwoman'
>>> mo3 = batRegex.search('The Adventures of Batwowowowoman')
>>> mo3.group()
'Batwowowowoman'
对于 'Batman'
, 正则表达式的(wo)*
部分匹配 wo
的零个实例。 对于'Batwoman'
,(wo)*
匹配 wo
的一个实例。 对于 'Batwowowowoman'
,(wo)*
匹配 wo
的4个实例。
如果需要匹配真正的星号字符, 就在正则表达式的星号字符前加上倒斜杠,即
\*
。
1.3.5. 用加号匹配一次或多次¶
*
意味着“匹配零次或多次”,+
(加号)则意味着
“匹配一次或多次”。星号不要求分组出现在匹配的字符串中,
但加号不同,加号前面的分组必须“至少出现一次”。
这不是可选的。在交互式环境中输入以下代码,
把它和前一节的星号正则表达式进行比较:
>>> batRegex = re.compile(r'Bat(wo)+man')
>>> mol = batRegex.search('The Adventures of Batwowoman')
>>> mol.group()
'Batwowoman'
>>> mo2 = batRegex.search('The Adventures of Batwowowowoman')
>>> mo2.group()
'Batwowowowoman'
>>> mo3 = batRegex.search('The Adventures of Batman')
>>> mo3 == None
True
正则表达式 Bat(wo)+man
不会匹配 字符串
'The Adventures of Batman'
, 因为加号要求 wo
至少出现一次。
如果需要匹配真正的加号字符, 在加号前面加上倒斜杠实现转义:\+
。
1.3.6. 用花括号匹配特定次数¶
如果想要一个分组重复特定次数, 就在正则表达式中该分组的后面,
跟上花括号包围的数字。例如, 正则表达式 (Ha){3}
将匹配
字符串'HaHaHa'
,但不会匹配'HaHa'
, 因为后者只重复了
(Ha)
分组两次。
除了一个数字,还可以指定一个范围, 即在花括号中写下一个最小值、
一个逗号和一个最大值。例如, 正则表达式 (Ha){3,5}
将匹配'HaHaHa'
、 'HaHaHaHa'
和 'HaHaHaHaHa'
。
也可以不写花括号中的第一个或第二个数字, 不限定最小值或最大值。例如,
(Ha){3,}
将匹配3次或更多次实例, (Ha){,5}
将匹配0到5次实例。
花括号让正则表达式更简短。这两个正则表达式匹配同样的模式:
(Ha){3}
(Ha)(Ha)(Ha)
这两个正则表达式也匹配同样的模式:
(Ha){3,5}
((Ha)(Ha)(Ha))|((Ha)(Ha)(Ha)(Ha))|((Ha)(Ha)(Ha)(Ha)(Ha))
在交互式环境中输入以下代码:
>>> haRegex = re.compile(r'(Ha){3}')
>>> mol = haRegex.search('HaHaHa')
>>> mol.group()
'HaHaHa'
>>> mo2 = haRegex.search('Ha')
>>> mo2 == None
True
这里, (Ha){3}
匹配'HaHaHa'
,
但不匹配'Ha'
。因为它不匹配'Ha'
, 所以 search()
返回
None
。