
上一次在「正则表达式」一文中分享了正则表达式的基础内容,让大家了解到正则表达式的强大功能。
python自1.5版本起增加了re模块,re模块中提供了一些方法,可以方便在python语言中使用正则表达式,re模块使python语言拥有全部的正则表达式功能。
re模块的方法
python语言中把函数提供的功能叫做方法,re模块提供了各种各样的正则表达式方法。
re.match(pattern, string, flags=0)方法:如果string开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的匹配对象。如果没有匹配,就返回None.
>>> import re
>>> print(re.match('abc', 'abcdef').group()) # 匹配到开头
abc
>>> print(re.match('abc', 'defabc').group()) # 未未匹配开头,返回None
None
re.search(pattern, string, flags=0)方法:扫描整个字符串找到匹配样式的第一个位置(一旦匹配成功则停止匹配),并返回一个相应的匹配对象。如果没有匹配,就返回None.
>>> import re
>>> print(re.search('d+', 'ab12cd236ef').group()) # 返回第一个匹配
12
>>> print(re.search('d+', 'abcd236ef').group()) # 返回第一个匹配
236
re.match与re.search的区别:re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None,而re.search匹配整个字符串,直到找到一个匹配对象为止。
re.fullmatch(pattern, string, flags=0)方法:如果整个string匹配到正则表达式样式,就返回一个相应的匹配对象 ,否则就返回None.
>>> print(re.fullmatch('d+', 'ab12cd236ef')) # 未匹配成功
None
>>> print(re.fullmatch('d+', '236')) # 匹配整个字符串
<re.Match object; span=(0, 3), match='236'>
re.findall(pattern, string, flags=0)方法:搜索string,以列表的形式返回全部能匹配到的字串,对string从左到右进行扫描,按找到的顺序返回。
import re
>>> print(re.findall('(w=2u).*(l=1u)', 'n33 w=2u m=2 l=1u')) # 分组
[('w=2u', 'l=1u')]
>>> print(re.findall('d+', 'ab12cd236ef12')) # 匹配所有
['12', '236', '12']
如果样式里存在一到多个组,就返回一个组合列表;如果样式里有超过一个组合的话就是一个元组的列。re.split(pattern, string, maxsplit=0, flags=0)方法:用pattern分开string,如果在pattern中捕获到括号,那么所有的组里的文字也会包含在列表里。
import re
>>> print(re.split('d+', 'ab12cd236ef5678')) # 使用数字分割
['ab', 'cd', 'ef', '']
>>> print(re.split('d+', 'ab12cd236ef')) # 使用数字分割
['ab', 'cd', 'ef']
>>> print(re.split('(d+)', 'ab12cd236ef5678')) # 分组
['ab', '12', 'cd', '236', 'ef', '5678', '']
>>> print(re.split('(d+)', 'ab12cd236ef')) # 分组
['ab', '12', 'cd', '236', 'ef']
如果maxsplit非零,最多进行maxsplit次分隔,剩下的字符全部返回到列表的最后一个元素。
import re
>>> print(re.split('d+', 'ab12cd236ef5678', 2)) # 指定次数
['ab', 'cd', 'ef5678']
re.sub(pattern, repl, string, count=0, flags=0):使用repl替换string中每一个匹配的子串后返回替换后的字符串。可选参数count是要替换的最大次数,count必须是非负整数,如果忽略这个参数,或者设置为0,所有的匹配都会被替换。
import re
>>> print(re.sub(r'd+', ',', 'ab12cd236ef5678'))
ab,cd,ef,
>>> print(re.sub(r'(w=2u)(.*)(l=1u)', r'1*0.923*0.8', 'n33 w=2u m=2 l=1u'))
n33 w=2u*0.9 m=2 l=1u*0.8
repl可以是字符串或函数,如为字符串,则其中任何反斜杠转义序列都会被处理。也就是说,n会被转换为一个换行符,r会被转换为一个回车附,依此类推。re.sub()方法用来实现电路设计中网表替换功能十分方便,可以按照需要替换器件参数,会经常使用。re.subn(pattern, repl, string, count=0, flags=0):行为与re.sub()相同,但是返回一个元组 (新的替换字符串,替换次数)。
import re
>>> print(re.subn(r'd+', ',', 'ab12cd236ef5678'))
('ab,cd,ef,', 3)
以上是re模块常用的方法,还有个别不常用的方法如果有需要可以参考re模块的官方文档。
编译正则表达式
绝大部分的正则表达式在使用前,总是会先将正则表达式编译,之后再进行操作,re模块提供re.compile(pattern, flags=0)方法将正则表达式的样式编译为一个正则表达式对象 (RegexObject).
import re
>>> pattern = re.compile(r'd+')
>>> print(type(pattern))
<class 're.Pattern'>
编译的正则表达式返回一个正则表达式对象可以用于匹配,这个对象的方法包括match(), search()以及其它方法等,与re模块的函数使用很类似,详细描述可以参考下面表格内容。
正则表达式对象的方法
方法 | 描述 |
pattern.search(string[,pos[, endpos]]) | 扫描整个string寻找第一个匹配的位置,并返回一个相应的匹配对象。 |
pattern.match(string[,pos[, endpos]]) | 如果string开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的匹配对象。 |
pattern.fullmatch(string[,pos[, endpos]]) | 如果整个string匹配这个正则表达式,就返回一个相应的匹配对象。 |
pattern.split(string,maxsplit=0) | 等价于split()函数,使用了编译后的样式。 |
pattern.findall(string[,pos[, endpos]]) | 类似函数findall(),使用了编译后样式,可以接收可选参数。 |
pattern.sub(repl,string, count=0) | 等价于sub() 函数,使用了编译后的样式。 |
pattern.subn(repl, string, count=0) | 等价于subn()函数,使用了编译后的样式。 |
pattern.groups | 捕获组合的数量。 |
pattern.pattern | 编译对象的原始样式字符串。 |
以上方法中可选参数pos给出了字符串中开始搜索的位置索引,默认为0。可选参数endpos限定了字符串搜索的结束,它假定字符串长度endpos, 所以只有从pos到endpos-1的字符会被匹配。如果endpos小于pos,就不会有匹配产生。
import re
>>> pattern = re.compile(r'd+')
>>> pattern.search('ab12dc236ef5678').group()
'12'
>>> pattern.match('12dc236ef5678').group()
'12'
>>> pattern.fullmatch('5678').group()
'5678'
>>> pattern.findall('ab12dc236ef5678')
['12', '236', '5678']
>>> pattern.split('ab12dc236ef5678')
['ab', 'dc', 'ef', '']
>>> pattern.sub(',', 'ab12dc236ef5678')
'ab,dc,ef,'
正则表达式的编译行为可以通过指定标记的值来改变,通过指定标记值可以控制匹配的模式,多个标志值可以通过位操作符OR( | )来指定。
编译行为修饰符
修饰符 | 描述 |
re.A | 让w, W, b, B, d, D, s 和 S 只匹配ASCII,而不是Unicode. |
re.DEBUG | 显示编译时的debug信息。 |
re.I | 使匹配对大小写不敏感 |
re.L | 由做本地化识别匹配,不推荐使用。 |
re.M | 多行匹配,影响^和$. |
re.S | 使.匹配包括换行在内的所有字符。 |
re.X | 允许表达式分段和添加注释,以便将正则表达式写得更易于理解。 |
匹配对象的方法
使用match()或者search()方法(无论使用编译的样式还是未编译的样式)返回值是一个匹配对象。
如果没有匹配的话match()和search()返回None ,如果匹配成功,匹配对象总是有一个布尔值True,匹配对象支持以下方法和属性:
Match.group([group1, ...]):返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,整个匹配都被返回。如果一个组号是负数,或者大于样式中定义的组数,一个IndexError索引错误就raise。
import re
>>> pattern = re.compile(r'(d+).*?(d+).*?(d+)') # 非贪婪匹配
>>> match_pattern = pattern.search('ab12dc236ef5678') # 分组
>>> match_pattern.groups()
('12', '236', '5678')
>>> match_pattern.group(0)
'12dc236ef5678'
>>> match_pattern.group(1) # 第1个匹配
'12'
>>> match_pattern.group(3) # 第3个匹配
'5678'
>>> match_pattern.group(2, 3) # 第2个和3个匹配
('236', '5678')
如果正则表达式使用了(?P<name>…)语法,groupN参数就也可能是命名组的名字。如果一个参数在样式中未定义,一个 IndexError就raise。
import re
>>> pattern = re.compile(r'(?P<first>d+).*?(?P<second>d+).*?(?P<last>d+)') # 非贪婪匹配,为分组命名
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.group('second') # 选择分组
'236'
Match.groups(default=None):返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。default参数用于不参与匹配的情况,默认为None。
import re
>>> pattern = re.search(r'(d+).*?(d+).*?(d+)', 'ab12dc236ef5678')
>>> pattern.group(2)
'236'
>>> pattern.groups()
('12', '236', '5678')
Match.groupdict(default=None):返回一个字典,包含了所有的命名子组,key就是组名,default参数用于不参与匹配的组合,默认为None。例如:
import re
>>> pattern = re.compile(r'(?P<first>d+).*?(?P<second>d+).*?(?P<last>d+)') # 非贪婪匹配,为分组命名
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.groupdict() # 返回字典
{'first': '12', 'second': '236', 'last': '5678'}
Match.start([group]),Match.end([group]):返回group匹配到的字串的开始和结束索引。group默认为0(意思是整个匹配的子串)。
import re
>>> pattern = re.compile(r'(d+).*?(d+).*?(d+)')
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.end()
15
>>> match_pattern.start()
2
Match.span([group]):对于一个匹配m ,返回一个二元组 (m.start(group), m.end(group)) 。如果group没有在这个匹配中,就返回 (-1, -1) 。group默认为(0意思是整个匹配)。
import re
>>> pattern = re.compile(r'(d+).*?(d+).*?(d+)')
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.span(2)
(6, 9)
Match.pos,Match.endpos:返回正则引擎在字符串中搜索一个匹配的索引位置。
import re
>>> pattern = re.compile(r'(d+).*?(d+).*?(d+)')
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.pos # 匹配从字符串头开始
0
>>> match_pattern.endpos # 匹配到字符串尾结束
15
Match.lastindex:捕获组的最后一个匹配的整数索引值,如果没有匹配产生,则为None.
import re
>>> pattern = re.compile(r'(d+).*?(d+).*?(d+)')
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.lastindex
3
Match.lastgroup:最后一个匹配的命名组名字,如果没有产生匹配则为None.Match.re:返回产生这个实例的正则对象,这个实例是由正则对象的 match()或search()方法产生的。Match.string:传递到match()或search()方法的字符串。
import re
>>> pattern = re.compile(r'(?P<first>d+).*?(?P<second>d+).*?(?P<last>d+)')
>>> match_pattern = pattern.search('ab12dc236ef5678')
>>> match_pattern.lastgroup
'last'
>>> match_pattern.re
re.compile('(?P<first>d+).*?(?P<second>d+).*?(?P<last>d+)')
>>> match_pattern.string
'ab12dc236ef5678'
以上示例小目同学在python 3.7版本验证过,部分方法可能涉python版本问题,如有问题可以「在文章评论处」讨论。
re模块的有关内容也可以参考官方手册,有更详细的示例和解释,如有异议请以官方手册为准。
除了官方提供的re模块外,还可以使用第三方模块:regex,与re模块兼容, 同时还提供了额外的功能和更全面的Unicode支持。对于大多数用户来说re模块已经满足需要,这里不对regex模块做介绍。
简介
作者:小目(wx:student_xiaomu)
微信公众号:ICSkillSharing,是一个共同学习的平台,分享最新IT类资讯、原创内容、IC中脚本语言的教程与使用心得、模拟IC新手在学习过程中遇到的问题等,与大家一起成长进步!