返回介绍

7.3 用正则表达式匹配更多模式

发布于 2024-01-22 21:44:06 字数 5300 浏览 0 评论 0 收藏 0

既然你已知道用Python创建和查找正则表达式对象的基本步骤,就可以尝试一些更强大的模式匹配功能了。

7.3.1 利用括号分组

假定想要将区号从电话号码中分离。添加括号将在正则表达式中创建“分组”:(\d\d\d)-(\d\d\d-\d\d\d\d)。然后可以使用group()匹配对象方法,从一个分组中获取匹配的文本。

正则表达式字符串中的第一对括号是第1组。第二对括号是第2组。向group()匹配对象方法传入整数1或2,就可以取得匹配文本的不同部分。向group()方法传入0或不传入参数,将返回整个匹配的文本。在交互式环境中输入以下代码:

>>> phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
>>> mo = phoneNumRegex.search('My 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'

如果想要一次就获取所有的分组,请使用groups()方法,注意函数名的复数形式。

>>> 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)')
>>> mo = phoneNumRegex.search('My phone number is (415) 555-4242.')
>>> mo.group(1)
'(415)'
>>> mo.group(2)
'555-4242'

传递给re.compile()的原始字符串中,(和)转义字符将匹配实际的括号字符。

7.3.2 用管道匹配多个分组

字符|称为“管道”。希望匹配许多表达式中的一个时,就可以使用它。例如,正则表达式r'Batman|Tina Fey'将匹配'Batman'或'Tina Fey'。

如果Batman和Tina Fey都出现在被查找的字符串中,第一次出现的匹配文本,将作为Match对象返回。在交互式环境中输入以下代码:

>>> heroRegex = re.compile (r'Batman|Tina Fey')
>>> mo1 = heroRegex.search('Batman and Tina Fey.')
>>> mo1.group()
'Batman'

>>> mo2 = heroRegex.search('Tina Fey and Batman.')
>>> mo2.group()
'Tina Fey'

注意

利用findall()方法,可以找到“所有”匹配的地方。这在7.5节“findall()方法”中讨论。

也可以使用管道来匹配多个模式中的一个,作为正则表达式的一部分。例如,假设你希望匹配'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(1)只是返回第一个括号分组内匹配的文本'mobile'。通过使用管道字符和分组括号,可以指定几种可选的模式,让正则表达式去匹配。

如果需要匹配真正的管道字符,就用倒斜杠转义,即|。

7.3.3 用问号实现可选匹配

有时候,想匹配的模式是可选的。就是说,不论这段文本在不在,正则表达式都会认为匹配。字符?表明它前面的分组在这个模式中是可选的。例如,在交互式环境中输入以下代码:

>>> batRegex = re.compile(r'Bat(wo)?man')
>>> mo1 = batRegex.search('The Adventures of Batman')
>>> mo1.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')
>>> mo1 = phoneRegex.search('My number is 415-555-4242')
>>> mo1.group()
'415-555-4242'
>>> mo2 = phoneRegex.search('My number is 555-4242')
>>> mo2.group()
'555-4242'

你可以认为?是在说,“匹配这个问号之前的分组零次或一次”。

如果需要匹配真正的问号字符,就使用转义字符\?。

7.3.4 用星号匹配零次或多次

*(称为星号)意味着“匹配零次或多次”,即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复。让我们再来看看Batman的例子。

>>> batRegex = re.compile(r'Bat(wo)*man')
>>> mo1 = batRegex.search('The Adventures of Batman')
>>> mo1.group()
'Batman'

>>> 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个实例。

如果需要匹配真正的星号字符,就在正则表达式的星号字符前加上倒斜杠,即*。

7.3.5 用加号匹配一次或多次

*意味着“匹配零次或多次”,+(加号)则意味着“匹配一次或多次”。星号不要求分组出现在匹配的字符串中,但加号不同,加号前面的分组必须“至少出现一次”。这不是可选的。在交互式环境中输入以下代码,把它和前一节的星号正则表达式进行比较:

>>> batRegex = re.compile(r'Bat(wo)+man')
>>> mo1 = batRegex.search('The Adventures of Batwoman')
>>> mo1.group()
'Batwoman'

>>> 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至少出现一次。

如果需要匹配真正的加号字符,在加号前面加上倒斜杠实现转义:+。

7.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}')
>>> mo1 = haRegex.search('HaHaHa')
>>> mo1.group()
'HaHaHa'

>>> mo2 = haRegex.search('Ha')
>>> mo2 == None
True

这里,(Ha){3}匹配'HaHaHa',但不匹配'Ha'。因为它不匹配'Ha',所以search()返回None。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文