Python中的模式匹配与正则表达式
先决条件: Python中的正则表达式
您可能熟悉通过按 ctrl-F 并输入您要查找的单词来搜索文本。正则表达式更进一步:它们允许您指定要搜索的文本模式。
正则表达式,简称正则表达式,是对文本模式的描述。例如,正则表达式中的 \d 代表数字字符,即 0 到 9 之间的任何单个数字。
- 以下正则表达式在Python中用于匹配由三个数字、一个连字符、另外三个数字、另一个连字符和四个数字组成的字符串。
Any other string would not match the pattern. \d\d\d-\d\d\d-\d\d\d\d
- 正则表达式可以更加复杂。例如,在模式后的大括号 ({3}) 中添加 3 就像在说“匹配此模式三遍”。所以稍微短一点的正则表达式
\d{3}-\d{3}-\d{4}
(它匹配正确的电话号码格式。)
创建正则表达式对象
Python中的所有正则表达式函数都在 re 模块中
import re
要创建与电话号码模式匹配的 Regex 对象,请在交互式 shell 中输入以下内容。
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
现在 phoneNumRegex 变量包含一个 Regex 对象。
匹配正则表达式对象
Regex 对象的 search() 方法搜索传递给该正则表达式的任何匹配字符串。 Match 对象有一个 group() 方法,该方法将从搜索的字符串中返回实际匹配的文本。
# Python program to illustrate
# Matching regex objects
import re
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('My number is 415-555-4242.')
print('Phone number found: ' + mo.group())
输出:
Phone number found: 415-555-4242
正则表达式匹配步骤
虽然在Python中使用正则表达式有几个步骤,但每个步骤都相当简单。
- 使用 import re 导入正则表达式模块。
- 使用 re.compile()函数创建一个 Regex 对象。 (记得使用原始字符串。)
- 将要搜索的字符串传递给 Regex 对象的 search() 方法。这将返回一个匹配对象。
- 调用 Match 对象的 group() 方法以返回实际匹配文本的字符串。
用括号分组
- 匹配对象:假设您想将区号与电话号码的其余部分分开。添加括号将在正则表达式中创建组:(\d\d\d)-(\d\d\d-\d\d\d\d)。然后,您可以使用 group() 匹配对象方法从一组中获取匹配的文本。
# Python program to illustrate # Matching regex objects # with grouping import re phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') mo = phoneNumRegex.search('My number is 415-555-4242.') print(mo.group(1))
输出:
'415'
- 一次检索所有组:如果您想一次检索所有组,请使用 groups() 方法——注意名称的复数形式。
# Python program to illustrate # Matching regex objects # with groups import re phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') mo = phoneNumRegex.search('My number is 415-555-4242.') print(mo.groups())
输出:
('415', '555-4242')
- 使用 mo.groups : mo.groups() 将返回一个包含多个值的元组,您可以使用多重赋值技巧将每个值分配给一个单独的变量,如下面的 areaCode, mainNumber = mo.groups() 行所示。
# Python program to illustrate # Matching regex objects # with mo.groups() import re phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') mo = phoneNumRegex.search('My number is 415-555-4242.') areaCode, mainNumber = mo.groups() print(mainNumber)
输出:
'555-4242'
- 匹配括号:括号在正则表达式中具有特殊含义,但是如果您需要匹配文本中的括号,该怎么办。例如,您尝试匹配的电话号码可能在括号中设置了区号。在这种情况下,您需要使用反斜杠转义 ( 和 )字符。在交互式 shell 中输入以下内容:
# Python program to illustrate # Matching regex objects # with grouping import re 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)'
传递给 re.compile() 的原始字符串中的 \( 和 \) 转义字符将匹配实际的括号字符。
将多个组与管道匹配
该|字符称为管道。您可以在任何想要匹配多个表达式之一的地方使用它。例如,正则表达式 r'Batman|Tina Fey' 将匹配 'Batman' 或 'Tina Fey'。
当搜索到的字符串中同时出现 Batman 和 Tina Fey 时,第一次出现的匹配文本将作为 Match 对象返回。在交互式 shell 中输入以下内容:
# Python program to illustrate # Matching regex objects # with multiple Groups with the Pipe import re heroRegex = re.compile (r'Batman|Tina Fey') mo1 = heroRegex.search('Batman and Tina Fey.') print(mo1.group())
输出:
'Batman'
用大括号匹配特定的重复
如果您有一个想要重复特定次数的组,请在您的正则表达式中使用大括号中的数字跟随该组。例如,正则表达式 (Ha){3} 将匹配字符串'HaHaHa',但不会匹配 'HaHa',因为后者只有 (Ha) 组的两次重复。
您可以通过在大括号之间写入最小值、逗号和最大值来指定范围,而不是一个数字。例如,正则表达式 (Ha){3, 5} 将匹配 'HaHaHa'、'HaHaHaHa' 和 'HaHaHaHaHa'。
您还可以省略大括号中的第一个或第二个数字,以使最小值或最大值不受限制。例如,(Ha){3, } 将匹配 (Ha) 组的三个或更多实例,而 (Ha){, 5} 将匹配零到五个实例。花括号可以帮助使您的正则表达式更短。这两个正则表达式匹配相同的模式:
(Ha){3} (Ha)(Ha)(Ha)
这两个正则表达式也匹配相同的模式:
(Ha){3, 5} ((Ha)(Ha)(Ha))|((Ha)(Ha)(Ha)(Ha))|((Ha)(Ha)(Ha)(Ha)(Ha))
在交互式 shell 中输入以下内容:
# Python program to illustrate # Matching Specific Repetitions # with Curly Brackets import re haRegex = re.compile(r'(Ha){3}') mo1 = haRegex.search('HaHaHa') print(mo1.group())
输出:
'HaHaHa'
# Python program to illustrate # Matching Specific Repetitions # with Curly Brackets import re haRegex = re.compile(r'(Ha){3}') mo2 = haRegex.search('Ha')== None print(mo2)
输出:
True
在这里,(Ha){3} 匹配 'HaHaHa' 但不匹配 'Ha'。由于它不匹配 'Ha',因此 search() 返回 None。
与问号的可选匹配
有时,您只想选择匹配一种模式。也就是说,无论该位文本是否存在,正则表达式都应该找到匹配项。 ?字符将其前面的组标记为模式的可选部分。例如,在交互式 shell 中输入以下内容:
# Python program to illustrate # optional matching # with question mark(?) import re batRegex = re.compile(r'Bat(wo)?man') mo1 = batRegex.search('The Adventures of Batman') print(mo1.group())
输出:
'Batman'
# Python program to illustrate # optional matching # with question mark(?) import re batRegex = re.compile(r'Bat(wo)?man') mo2 = batRegex.search('The Adventures of Batwoman') print(mo2.group())
输出:
'Batwoman'
禾)?正则表达式的一部分意味着模式 wo 是一个可选组。正则表达式将匹配其中包含零个实例或一个 wo 实例的文本。这就是为什么正则表达式同时匹配“蝙蝠女侠”和“蝙蝠侠”的原因。
你能想到吗?就像说, “匹配这个问号之前的组中的零个或一个。”
如果您需要匹配实际的问号字符,请使用 \? 对其进行转义。匹配零个或多个与星
*(称为星号或星号)表示“匹配零个或多个”——星号之前的组可以在文本中出现任意次数。它可以完全不存在或一遍又一遍地重复。让我们再看看蝙蝠侠的例子。
# Python program to illustrate # matching a regular expression # with asterisk(*) import re batRegex = re.compile(r'Bat(wo)*man') mo1 = batRegex.search('The Adventures of Batman') print(mo1.group())
输出:
'Batman'
#python program to illustrate #matching a regular expression #with asterisk(*) import re batRegex = re.compile(r'Bat(wo)*man') mo2 = batRegex.search('The Adventures of Batwoman') print(mo2.group())
输出:
'Batwoman'
# Python program to illustrate # matching a regular expression # with asterisk(*) import re batRegex = re.compile(r'Bat(wo)*man') mo3 = batRegex.search('The Adventures of Batwowowowoman') print(mo3.group())
输出:
'Batwowowowoman'
对于“蝙蝠侠”,正则表达式的 (wo)* 部分匹配字符串中 wo 的零个实例;对于“蝙蝠女侠”, (wo)* 匹配 wo 的一个实例;对于“Batwowowowoman”,(wo)* 匹配 wo 的四个实例。
如果您需要匹配实际的星号,请在正则表达式字符的星号前加上反斜杠 \*。
与 Plus 匹配一个或多个
* 表示“匹配零个或多个”,而 +(或加号)表示“匹配一个或多个”。与不要求其组出现在匹配字符串中的星号不同,加号之前的组必须至少出现一次。这不是可选的。在交互式 shell 中输入以下内容,并将其与上一节中的星型正则表达式进行比较:
# Python program to illustrate # matching a regular expression # with plus(+) import re batRegex = re.compile(r'Bat(wo)+man') mo1 = batRegex.search('The Adventures of Batwoman') print(mo1.group())
输出:
'Batwoman'
# Python program to illustrate # matching a regular expression # with plus(+) import re batRegex = re.compile(r'Bat(wo)+man') mo2 = batRegex.search('The Adventures of Batwowowowoman') print(mo2.group())
输出:
'Batwowowowoman'
batRegex = re.compile(r'Bat(wo)+man')
# Python program to illustrate # matching a regular expression # with plus(+) import re batRegex = re.compile(r'Bat(wo)+man') mo3 = batRegex.search('The Adventures of Batman')== None print(mo3)
输出:
True
正则表达式 Bat(wo)+man 将不匹配字符串“蝙蝠侠历险记”,因为加号至少需要一个 wo。
如果您需要匹配实际的加号字符,请在加号前加上反斜杠以将其转义:\+。
- 匹配对象:假设您想将区号与电话号码的其余部分分开。添加括号将在正则表达式中创建组:(\d\d\d)-(\d\d\d-\d\d\d\d)。然后,您可以使用 group() 匹配对象方法从一组中获取匹配的文本。