Python 正则表达式提供了强大的模式匹配能力,可以处理各种复杂的文本匹配需求。
通过字符类[abc]
可以匹配特定字符集合,量词如、+、?
和{m,n}
能灵活控制匹配次数,
而分组捕获()
则可将匹配内容单独提取。特殊模式如非贪婪匹配?、
正向断言(?=...
)和命名分组(?P<name>...
)进一步扩展了匹配的可能性。
这些模式可以自由组合,配合re
模块的search
、findall
等方法,
能够精准实现文本查找、内容提取、格式验证等操作。
无论是简单的字符串匹配还是复杂的文本分析,正则表达式都能提供优雅高效的解决方案,是处理文本数据的利器。
既然已知用 Python 创建和查找正则表达式对象的基本步骤, 就可以尝试一些更强大的模式匹配功能了。
利用括号分组
假定想要将区号从电话号码中分离。添加括号将在正则表达式中创建“分组”:
(\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'
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()
方法,可以找到“所有”匹配的地方。
也可以使用管道来匹配多个模式中的一个,作为正则表达式的一部分。
例如,假设希望匹配 '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'
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'
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个实例。
如果需要匹配真正的星号字符,
就在正则表达式的星号字符前加上倒斜杠,即 \*
。
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
除了一个数字,还可以指定一个范围,
即在花括号中写下一个最小值、
一个逗号和一个最大值。例如,
正则表达式 (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
。