在了解了有关正则表达式的全部知识后,开始查看Python当前如何通过re模块来支持正则表达式。
1.1.1 re模块:核心函数和方法
x下表列出了来自re模块的更多常见函数和方法,它们中的大多函数与已经编译的正则表达式(regex object)和正则匹配对象(regex match object)的方法同名并且具有相同的功能。本次将介绍两个主要的函数/方法-match()和search(),以及compile()函数。
1.1.2 使用cpmpile()函数编译正则表达式
后续将要介绍的几乎所有的re模块函数都可以作为regex对象的方法。注意,尽管推荐预编译,但它并不是必需的。如果需要编译,就使用编译过的方法,如果不需要编译,就使用函数。幸运的是,不管使用函数还是方法,它们的名字都是相同的。
对于一些特别的正则表达式编译,可选的标记可能以参数给出,这些标记允许不区分大小写的匹配,使用系统的本地设置来匹配字母数字,等等。
这些标记也可以作为参数适用于大多数re模块函数。如果想要在方法中使用这些标记,它们必须已经集成到已编译的正则表达式对象之中,或者需要使用直接嵌入到正则表达式本身的(?F)标记。
1.1.3 匹配对象以及group()和group()方法
D当处理正则表达式时,处理正则表达式对象之外,还有另一个对象类型:匹配对象。这些是成功调用match()或者search()返回的对象。匹配对象由两种主要的方方法:group()和groups()。
group()要么返回整个匹配对象,要么根据要求返回特定子组。groups则仅返回一个包括唯一或者全部子组的元组。如果没有子组的要求,那么当group()仍然返回的是整个匹配时,groups()返回的是一个空元组。
1.1.4 使用match()方法匹配字符串
match()是将要介绍的第一个re模块和正则表达式对象(regex object)方法。match()函数试图从字符串的起始部分对模式进行匹配。如果匹配成功,就返回一个匹配对象;如果匹配失败,就返回None,匹配对象的group()方法能够用于显示那个成功的匹配。下面是如果运用match()(以及group())的一个示例:
m = re.match('foo', 'foo') #模式匹配字符串
if m is not None:
m.group()
只要模式从字符串的起始位置部分开始匹配,即使字符串比模式长,匹配也仍然能够成功。
例如,模式“foo”将在字符串“food on table”中找到一个匹配,因为它是从字符串的起始部分进行匹配的。
m = re.match('foo', 'food on table') #匹配成功
m.group()
k可以看到,尽管字符串比模式要长,但从字符串的起始部分开始匹配就会成功。
1.1.5 使用search()在一个字符串中查找模式(搜索和匹配的对比)
其实,想要搜索的模式出现在一个字符串中间部分的概率,远大于出现在字符串起始部分的概率。这也就是search()派上用场的时候。search()的工作方式与match()完全一致,不同之处在于search()会用它的字符串参数,在任意位置对给定正则表达式模式搜索第一次出现的匹配情况。如果搜索到就成功的匹配,就会返回一个匹配对象;否则,返回None。
w我们再次举例说明match()和search()之间的差别,以匹配一个更长的字符串为例:
m = re.match('foo', 'seafood') #匹配失败
if m is not None:
...
可以看到,此处匹配失败。match()试图从字串的起始部分开始匹配,但是字符串的起始是“s”,所以匹配失败。search()函数不但会搜索模式在字符串中的第一次出现的位置,而且严格地对字符串从左到右搜索。
m = re.search('foo', 'seafood')
if m is not None:
m.group()
1.1.6 匹配多个字符串
在前面,我们在正则表达式bat|bet|bit中使用了择一匹配(|)符号。如下为在Python中使用正则表达式的方法。
bt = 'bat|bet|bit'
m = re.match(bt, 'bat')
if m is not None: m.group()
...
'bat'
m = re.match(bt, 'blt')
if m is not None:m.group() #对于‘blt’没有匹配
...
m = re.match(bt, 'he bit me')
if m is not None: m,group() #不能匹配字符串
m = re.search(bt, 'he bit me!')
if m is not None: m.group()
...
'bit'
1.1.7 匹配任何单个字符
点号(.)不能匹配一个换行符\n或者非字符,也就是说,一个空字符。
anyend = '.end'
m = re.match(anyend, 'bend')
if m is not None: m.group()
...
'bend'
m = re.match(anyend, 'end') #不匹配任何字符
if m is not None: m.group()
...
m = re.match(anyend, '\nend')
if m is not None: m.group()
...
m = re.search('.end', 'The end.') #在搜素中匹配' '
if m is not None: m.group()
...
' end'
x下面的示例在正则表达式中搜素一个真正的句号(小数点),而我们通过一个反斜杠对句点的功能进行转义:
patt314 = ‘3.14’ #表示正则表达式的点号
pi_patt = '3\.14' #表示点面量的点号(dec.point)
m = re.match(pi_patt, '3.14') #精确匹配
if m is not None: m.group()
...
'3.14'
m = re.match(patt314, '3014') #点号匹配‘0’
if m is not None: m.group()
...
'3014'
m = re.match(patt314, '3.14')
if m is not None: m.group()
...
'3.14'
1.1.8 创建字符集([ ])
m = re.match('[cr][23][dp][o2]', 'c3po') #匹配‘c3po’
if m is not None: m.group()
...
'c3po'
1.1.9 重复、特殊字符以及分组
正则表达式中最常见的情况包括特殊字符的使用、正则表达式模式的重复出现,以及使用圆括号对匹配模式的各个部分进行部分和提取操作。
patt = '\w+@(\w+\.)?\w+\.com'
re.match(patt, 'nobody@xxx.com').group()
'nobody@xxx.com'
re.match(patt, 'nobody@www.www.com').group()
'nobody@www.www.com'
j接下来,用以下模式进一步拓展该示例,允许任意数量的中间域名存在。请特别注意细节的变化,将‘?’改为‘’,:‘’\w+@(\w+.)\w+.com’。
patt = ''\w+@(\w+\.)*\w+\.com'
re.match(patt, 'nobody@www.xxx.yyy.zzz.com').group()
'nobody@www.xxx.yyy.zzz.com'
m = re.match('\w\w\w-\d\d\d', 'abc-123')
if m is not None: m.group()
...
'abc-123'
现在,将修改前面讨论过的正则表达式,使该正则表达式能够提取字母数字字符串和数字。如下所示,请注意如何使用group()方法访问每个独立的子组以及groups()方法获取一个包含所以匹配子组的元组。
m = re.match('(\w\w\w)-(\d\d\d)', 'abc-123')
m.group()
'abc-123'
m.group(1)
'abc'
m.group(2)
'123'
m.groups()
('abc', '123')
1.1.10 匹配字符串的起始和结尾以及单词边界
r如下示例突出表示位置的正则表达式操作符。该操作符更多用于表示搜素而不是匹配,因为match()总是从字符串开始位置进行匹配的。
m = re.search('^The', 'The end.')
if m is not None: m.group()
...
'The'
m = re.search('^The', 'end. The')
if m is not None: m.group()
...
m = re.search(r'\bthe', 'bite the dog')
if m is not None: m.group()
...
'the'
m = re.search(r'\bthe', ' bitethe dog')
if m is not None: m.group()
...
m = re.search(r'\Bthe', 'bitethe dog')
if m is not None: m.group()
...
'the'
1.1.11 使用findall()和finditer()查找每一次出现的位置
findall() | finditer() | |
---|---|---|
含义 | 查询字符串中某个正则表达式模式全部的非重复出现情况。这与search()在执行字符串搜索时类似,但与match()和search()的不同之处在于,findall()总是返回一个列表 | 这是一个与findall()函数类似但是更节省内存的变体。两者之间以及和其他变体函数之间的差异(很明显不同于返回的是一个迭代器还是列表)在于,和返回的匹配字符串相比,finditer()在匹配对象中迭代 |
补充 | 对一个成功的匹配,每个子组匹配是由findall()返回的结果列表中的每一个单一元素;对于多个成功的匹配,每一个子组匹配是返回一个元组中的单一元素,而且每个元组(每个元组都对应一个成功的匹配)是结果列表中的元素 | 使用finditer()哈桑农户有完成的所有额外工作都旨在获得它的输出来匹配findall()的输出 |
1.1.12 使用sub()和subn()搜索与替换
sub() | subn() | |||||||
共同点 | 都是将某字符串所有匹配正则表达式的部分进行某种形式的替换 | |||||||
不同点 | 返回替换后的字符串 | 不仅返回替换后的字符串,还返回一个表示替换的总数,替换后的字符串和表示替换的总数的数字一起作为一个拥有两个元素的元组返回 |
1.1.13 在限定模式上使用split()分隔符
re模块和正则表达式的对象方法split()对于相对应字符串的工作方式是类似的,但是与分割一个固定字符串相比,他们基于正则表达式的模式分隔字符串,为字符串功能添加一些额外的威力。如果你不想为每次模式的出现都分割字符串,就可以通过为max参数设定一个值(非零)来指定最大分割数。
1.1.14 拓展字符
略