正则表达式re模块

2019年9月5日 / 33次阅读 / Last Modified 2019年9月24日
re模块

正则表达式在编程领域的用途极其广泛,Python对其的支持,体现在标准的re模块中。本文集中介绍re模块中主要接口的使用方法,不对正则表达式本身的语法做介绍,这部分请同学们自行学习其他资料。

引入re模块

import re

re.match函数

match函数有一个细节需要特别关注,这个函数是从字符串的开头进行匹配,无需使用^。而且,此函数只要有一个匹配成功,就会返回匹配成功的Match对象。匹配不成功返回None。re.match函数很适合用来做某种匹配检查。请看下面的代码:

>>> re.match('\d{3,}','1234abcd')
<re.Match object; span=(0, 4), match='1234'>
>>> re.match('\d{3,}','12abcd')
>>>
>>> re.match('\d{3}$','12abcd56789')  # $ is no use
>>> re.match('\d{3}$','789')
<re.Match object; span=(0, 3), match='789'>
>>> re.match('\d{3}$','6789')
>>>

在re.match函数中使用正则表达式 \d{3}$ ,只能去匹配3个数字,因为此函数一定是从字符串第1个字符开始匹配。下面这种用法很常见,用来判断某个字符串是否具有某种特征:

>>> stra = 'https://www.pynote.net'
>>> if not re.match('\s+', stra):
...     print('string starts by non-space')
... else:
...     print('space found at beginning')
...
string starts by non-space

如果想要获取到使用re.match函数匹配的子串,可以这样:

>>> res = re.match('\d+','12345abcde')
>>> if res is not None: print(res.group())
...
12345

re.search函数

re.search函数就不再局限在从字符串的开始位置进行匹配,可以从任意位置开始匹配,回到search the match的本质。在正则表达式中,^和$都可以正常使用。跟re.match函数一样的地方是,search也只是从左到右匹配一次就返回,如果没有匹配,返回None。

>>> re.search('\d+','12345abcde')
<re.Match object; span=(0, 5), match='12345'>
>>> re.search('\d+','abcde12345')
<re.Match object; span=(5, 10), match='12345'>
>>>
>>> re.search('\d+$','abcde12345')
<re.Match object; span=(5, 10), match='12345'>
>>> re.search('^\d+','abcde12345')
>>> re.search('^\d+','12345abcde')
<re.Match object; span=(0, 5), match='12345'>
>>>
>>> re.search('\d+','12345abcde12345')
<re.Match object; span=(0, 5), match='12345'>

如果要获取re.search函数匹配的子串,还是使用Match对象的group函数:

>>> res = re.search('\w','!@#$%^&*5d')
>>> res.group()
'5'

re.findall函数

re.findall函数会按照正则表达式,找出字符串中所有匹配的子串。(re.match和re.search都只是从左到右找到一个匹配就返回)

>>> re.findall('\d+','123abc456jkl')
['123', '456']
>>> re.findall('@','123abc456jkl')
[]  # no match
>>> re.findall('^\d+','123abc456jkl')
['123']
>>> re.findall('\d+$','123abc456jkl')
[]

re.findall函数返回一个list,如果没有匹配的子串,list为空。注意:.re.findall函数匹配出来的多个子串,不会再原字符串里面重叠(non-overlapping)

re.split函数

re.split函数用来分割字符串,分割依据是以正则表达式所代表的子串。比如下面的代码,用字母分割数字子串:

>>> re.split('[a-zA-Z]+','123abc456TYU789K1P90')
['123', '456', '789', '1', '90']
>>> re.split('[a-zA-Z]+','12345678')
['12345678']
>>> re.split('[a-zA-Z]+','abcdef')
['', '']
>>> re.split('[a-zA-Z]+','1abcdef9')
['1', '9']
>>> re.split('[a-zA-Z]+','')
['']
>>> re.split('[:,-]','123,jkl-897:qw')
['123', 'jkl', '897', 'qw']

注意返回的List对象中,存在一个或两个空串的情况。

re.sub函数

re.sub函数的作用,对正则表达式匹配到的子串进行替换。

>>> a = re.sub('\s+','_','i love write blog')
>>> a
'i_love_write_blog'
>>> b = re.sub('maixj','pynote','https://www.maixj.net')
>>> b
'https://www.pynote.net'
>>> c = re.sub('\d','p','abcd')
>>> c
'abcd'

re.sub函数,第1个参数是正则表达式,第2个参数要替换的内容,第3个参数是待处理的字符串。函数返回值是字符串,如果没有匹配,就没有替换,返回原字符串。

多行匹配

re模块的这些常用接口函数,均可以支持多行匹配,换行符\n也是一个可以被匹配的字符。(别被re.MULTILINE误导了)

>>> ts = """i am a boy,
... i love bloging.
... This is my www.pynote.net"""
>>> ts
'i am a boy,\ni love bloging.\nThis is my www.pynote.net'
>>> re.search('pynote.net', ts)
<re.Match object; span=(43, 53), match='pynote.net'>
>>> re.findall('i', ts)
['i', 'i', 'i', 'i', 'i']
>>> re.sub('bloging','blogging' ,ts)
'i am a boy,\ni love blogging.\nThis is my www.pynote.net'

分组

在正则表达式中使用括号(()),就形成了分组。对于Match对象,可以使用group 或 groups 函数来提取各个不同分组的匹配情况。

>>> res = re.match('(\d)(\d)', '12345abcde12345')
>>> res.group()
'12'
>>> res.group(1)
'1'
>>> res.group(2)
'2'
>>> res.groups()
('1', '2')

re.match从头开始匹配,(\d)(\d) 表示匹配两个数字,第1个数字为组1(分组从1开始),第2个数字为组2。返回Match对象res,group() 不带参数,表示获取完整的匹配,即在不分组的情况下匹配的子串。group(1)就是获取组1的匹配,group(2),就是获取组2的匹配,返回都是字符串。而groups()函数,返回一个tuple,包含所有组的匹配子串。

>>> res = re.search('(\w).*(\d)','pynote.net 12345')
>>> res.group()
'pynote.net 12345'
>>> res.group(1)
'p'
>>> res.group(2)
'5'
>>> res.groups()
('p', '5')

以上是re.search函数返回的Match对象,使用分组的示例代码。请注意分组2,为什么是 '5' ?而不是 '1' ? 因为贪婪匹配!

命名分组

上面分组的示例,都是非命名分组,使用数字123...来索引,我们还可以使用命名分组,效果是一样的:

>>> res = re.search('(?P\d+)', 'asdf89897asd98asdf')
>>> res.group()
'89897'
>>> res.group(1)
'89897'
>>> res.group('number')
'89897'
>>> res.groups()
('89897',)

定义命名分组的语法:(?P<name>)

贪婪匹配

Python的re模块做正则表达式匹配,默认是采用贪婪匹配的模式。贪婪匹配就是让每一个正则表达式的符号,尽可能多的匹配字符,直接不满足为止。正如上文的例子, (\w).*(\d) 中间的 .* 会尽可能多的匹配,直到最后剩下一个 5。再看一个例子:

>>> res = re.search('(\d+)(9+)','abc999999999')
>>> res.groups()
('99999999', '9')

虽然分组2的正则表达式是 9+,但分组2还是只匹配到一个数字9,前面的一串9,都被 \d+ 匹配走了。这就是贪婪匹配。

编译正则表达式

re.compile函数可以用来编译正则表达式。编译的作用在于:(1)检查某个正则表达式是否正确;(2)如果某个正则表达式在代码中频繁被使用,先编译后使用,可以加快代码执行速度。

>>> regular = re.compile('\d\d\d\d\d')
>>> regular.match('123456789').group()
'12345'
>>> regular.search('123456789').group()
'12345'
>>> regular.findall('1234567890')
['12345', '67890']
>>> regular.split('12345abcde12345kkkkk')
['', 'abcde', 'kkkkk']
>>> regular.sub('yyyyy','12345kkkkk')
'yyyyykkkkk'

以上就是对Python正则表达式re模块常用函数和方法的总结。

-- EOF --

本文链接:https://www.pynote.net/archives/1060

留言区

电子邮件地址不会被公开。 必填项已用*标注


前一篇:
后一篇:

More

麦新杰的Python笔记

Ctrl+D 收藏本页


©Copyright 麦新杰 Since 2019 Python笔记

go to top