【Python】Python正则匹配必须掌握的10个函数

机器学习初学者

共 8387字,需浏览 17分钟

 ·

2022-07-04 20:01

正则表达re模块共有12个函数,我将分类进行讲解,这样方便记忆与理解,先来看看概览:

search、match、fullmatch:查找一个匹配项

findall、finditer查找多个匹配项

split:分割

sub,subn:替换

compile函数、template函数: 将正则表达式的样式编译为一个 正则表达式对象


print(dir(re))[...... 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'template']


一、查找一个匹配项

查找并返回一个匹配项的函数有3个:search、match、fullmatch,他们的作用分别是:

search:查找任意位置的匹配项

match:必须从字符串开头匹配

fullmatch:整个字符串与正则完全匹配

1) search()

描述:在给定字符串中寻找第一个匹配正则表达式的子字符串,如果找到会返回一个Match对象,这个对象中的元素可以group()得到(之后将会介绍group的概念),如果没找到就会返回None。调用re.match,re.search方法或者对re.finditer结果进行遍历,输出的结果都是re.Match对象

语法:re.search(pattern, string, flags=0)

  • pattern 匹配的正则表达式

  • string 要匹配的字符串

  • flags 标志位,用于控制正则表达式的匹配方式

re.search(r"(\w)(.\d)","as.21").group()
's.2'

假设返回的Match对象为m,m.group()来取某组的信息,group(1)返回与第一个子模式匹配的单个字符串,group(2)等等以此类推,start()方法得到对应组的开始索引,end()得到对应组的结束索引,span()以元组形式给出对应组的开始和结束位置,括号中填入组号,不填入组号时默认为0。

匹配对象m方法有很多,几个常用的方法如下:

m.start() 返回匹配到的字符串的起使字符在原始字符串的索引

m.end() 返回匹配到的字符串的结尾字符在原始字符串的索引

m.group() 返回指定组的匹配结果

m.groups() 返回所有组的匹配结果

m.span() 以元组形式给出对应组的开始和结束位置

其中的组,是指用()括号括起来的匹配到的对象,比如下列中的"(\w)(.\d)",就是两个组,第一个组匹配字母,第二个组匹配.+一个数字。

m = re.search(r"(\w)(.\d)","as.21")m<re.Match object; span=(1, 4), match='s.2'>
m.group() s.2m.group(0)'s.2'm.group(1) #根据要求返回特定子组's'm.group(2)'.2'm.start()1m.start(2)#第二个组匹配的索引位置2m.groups()('s''.21')m.span()(1, 5)

2) match()

描述:必须从字符串开头匹配,同样返回的是Match对象,对应的方法与search方法一致,此处不再赘述。

语法:re.match(pattern, string, flags=0)

  • pattern   匹配的正则表达式

  • string  要匹配的字符串

  • flags   标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

#从头开始匹配,返回一个数字,发现报错,无法返回,因为不是数字开头的text = 'chi13putao14butu520putaopi666'pattern = r'\d+'re.match(pattern,text).group()AttributeError: 'NoneType' object has no attribute 'group'#从头开始匹配,返回一个单词,正常返回了开头的单词text = 'chi13putao14butu520putaopi666'pattern = r'[a-z]+'re.match(pattern,text).group()'chi'

3) fullmatch()

描述:整个字符串与正则完全匹配,同样返回的是Match对象,对应的方法与search方法一致,此处不再赘述

语法:(pattern, string, flags=0)

  • pattern   匹配的正则表达式

  • string  要匹配的字符串

  • flags   标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

#必须要全部符合条件才能匹配
re.fullmatch(r'[a-z]+','chiputao14').group()AttributeError: 'NoneType' object has no attribute 'group're.fullmatch(r'[a-z]+','chiputao').group()'chiputao'


二、查找多个匹配项

讲完查找一项,现在来看看查找多项吧,查找多项函数主要有:findall函数finditer函数

1)findall: 从字符串任意位置查找,返回一个列表

2)finditer:从字符串任意位置查找,返回一个迭代器

两个函数功能基本类似,只不过一个是返回列表,一个是返回迭代器。我们知道列表是一次性生成在内存中,而迭代器是需要使用时一点一点生成出来的,运行时占用内存更小。如果存在大量的匹配项的话,建议使用finditer函数,一般情况使两个函数不会有太大的区别。

1)findall

描述:返回字符串里所有不重叠的模式串匹配,以字符串列表的形式出现。

语法:re.findall(pattern, string, flags=0)

  • pattern   匹配的正则表达式

  • string  要匹配的字符串

  • flags   标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

import retext    = 'Python太强大,我爱学Python'pattern = 'Python're.findall(pattern,text)['Python', 'Python']#找出下列字符串中的数字text = 'chi13putao14butu520putaopi666'#\d+表示匹配任意数字pattern = r'\d+'re.findall(pattern,text)['13''14''666''520'
text = 'ab-abc-a-cccc-d-aabbcc'pattern = 'ab*'re.findall(pattern,text)['ab', 'ab', 'a', 'a', 'abb']#找到所有副词'''findall() 匹配样式 所有 的出现,不仅是像 search() 中的第一个匹配。比如,如果一个作者希望找到文字中的所有副词,他可能会按照以下方法用 findall()'''
text = "He was carefully disguised but captured quickly by police."re.findall(r"\w+ly", text)['carefully''quickly']

2)finditer()

描述:返回一个产生匹配对象实体的迭代器,能产生字符串中所有RE模式串的非重叠匹配。

语法:re.finditer(pattern, string, flags=0)

  • pattern   匹配的正则表达式

  • string  要匹配的字符串

  • flags   标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

m = re.finditer("Python","Python非常强大,我爱学习Python")m <callable_iterator at 0x18b5eca58c8>for i in m:    print(i.group(0))PythonPython
#找到所有副词和位置'''如果需要匹配样式的更多信息, finditer() 可以起到作用,它提供了 匹配对象 作为返回值,而不是字符串。继续上面的例子,如果一个作者希望找到所有副词和它的位置,可以按照下面方法使用 finditer()'''
text = "He was carefully disguised but captured quickly by police."for m in re.finditer(r"\w+ly", text): print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0)))
07-16: carefully
40-47: quic



三、匹配项分割

1)split()

描述:split能够按照所能匹配的字串将字符串进行切分,返回切分后的字符串列表

形式.切割功能非常强大

语法:re.split(pattern, string, maxsplit=0, flags=0)

  • pattern:匹配的字符串

  • string:需要切分的字符串

  • maxsplit:分隔次数,默认为0(即不限次数)

  • flags:标志位,用于控制正则表达式的匹配方式,flags表示模式,就是上面我们讲解的常量!支持正则及多个字符切割。

正则表达的分割函数与字符串的分割函数一样,都是split,只是前面的模块不一样,正则表达的函数为, ,用pattern分开string,maxsplit表示最多进行分割次数,

re.split(r";","var A;B;C:integer;")['var A', 'B', 'C:integer', '']
re.split(r"[;:]","var A;B;C:integer;")['var A', 'B', 'C', 'integer', '']
text = 'chi13putao14butu520putaopi666'pattern = r'\d+'re.split(pattern,text)['chi', 'putao', 'butu', 'putaopi', '']
line = 'aac bba ccd;dde eef,fff'#单字符切割re.split(r';',line)['aac bba ccd', 'dde eef,fff']
#两个字符以上切割需要放在 [ ] 中re.split(r'[;,]',line)['aac bba ccd', 'dde eef', 'fff']

#所有空白字符切割re.split(r'[;,\s]',line)['aac', 'bba', 'ccd', 'dde', '', '', 'eef', 'fff']#使用括号捕获分组,默认保留分割符re.split(r'([;])',line)['aac bba ccd', ';', 'dde eef,fff']
#不想保留分隔符,以(?:...)的形式指定re.split(r'(?:[;])',line)['aac bba ccd', 'dde eef,fff']

#不想保留分隔符,以(?:...)的形式指定re.split(r'(?:[;,\s])',line)['aac', 'bba', 'ccd', 'dde', '', '', 'eef', 'fff']

 

注意:str模块也有一个split函数 ,那这两个函数该怎么选呢?str.split函数功能简单,不支持正则分割,而re.split支持正则。关于二者的速度如何?来实际测试一下,在相同数据量的情况下使用re.split函数与str.split函数执行次数 与 执行时间 对比图:

#运行时间统计 只计算了程序运行的CPU时间,且每次测试时间有所差异
import time#统计次数n = 1000``start_t = time.perf_counter()for i in range(n):     re.split(r';',line)##re.splitend_t = time.perf_counter()print ('re.split: '+str(round(1000000*(end_t-start_t),2)))
start_t = time.perf_counter()for i in range(n): line.split(';')##str.splitend_t = time.perf_counter()print ('str.split: '+str(round(1000000*(end_t-start_t),2)))




通过上图对比发现,5000次循环以内str.split函数和re.split函数执行时间差异不大,而循环次数1000次以上后str.split函数明显更快,而且次数越多差距越大!

所以结论是,在不需要正则支持的情况下使用str.split函数更合适,反之则使用re.split函数。具体执行时间与测试数据有关!且每次测试时间有所差异


 

四、匹配项替换

替换主要有sub函数与subn函数两个函数,他们功能类似,不同点在于sub只返回替换后的字符串,subn返回一个元组,包含替换后的字符串和替换次数。

python 里面可以用 replace 实现简单的替换字符串操作,如果要实现复杂一点的替换字符串操作,需用到正则表达式。

re.sub用于替换字符串中匹配项,返回一个替换后的字符串,subn方法与sub()相同, 但返回一个元组, 其中包含新字符串和替换次数。

sub是substitute表示替换。

1)sub

描述:它的作用是正则替换。

语法:re.sub(pattern, repl, string, count=0, flags=0)

  • pattern:该参数表示正则中的模式字符串;

  • repl:repl可以是字符串,也可以是可调用的函数对象;如果是字符串,则处理其中的反斜杠转义。如果它是可调用的函数对象,则传递match对象,并且必须返回要使用的替换字符串

  • string:该参数表示要被处理(查找替换)的原始字符串;

  • count:可选参数,表示是要替换的最大次数,而且必须是非负整数,该参数默认为0,即所有的匹配都会被替换;

  • flags:可选参数,表示编译时用的匹配模式(如忽略大小写、多行模式等),数字形式,默认为0。

 

把字符串 aaa34bvsa56s中的数字替换为 *号

import rere.sub('\d+','*','aaa34bvsa56s')#连续数字替换'aaa*bvsa*s're.sub('\d','*','aaa34bvsa56s')#每个数字都替换一次'aaa**bvsa**s'#只天换一次count=1,第二次的数字没有被替换re.sub('\d+','*','aaa34bvsa56s',count=1)'aaa*bvsa56s'把chi13putao14butu520putaopi666中的数字换成...text = 'chi13putao14butu520putaopi666'pattern = r'\d+'re.sub(pattern,'...',text)'chi...putao...butu...putaopi...'
关于第二个参数的用法,我们可以看看下面的内容#定义一个函数def refun(repl): print(type(repl)) return('...')re.sub('\d+',refun,'aaa34bvsa56s')<class 're.Match'><class 're.Match'>'aaa...bvsa...s'从上面的例子看来,似乎没啥区别原字符串中有多少项被匹配到,这个函数就会被调用几次。至于传进来的这个match对象,我们调用它的.group()方法,就能获取到被匹配到的内容,如下所示:def refun(repl): print(type(repl),repl.group()) return('...')re.sub('\d+',refun,'aaa34bvsa56s')<class 're.Match'> 34<class 're.Match'> 56Out[113]: 'aaa...bvsa...s'这个功能有什么用呢?我们设想有一个字符串moblie18123456794num123,这个字符串中有两段数字,并且长短是不一样的。第一个数字是11位的手机号。我想把字符串替换为:moblie[隐藏手机号]num***。不是手机号的数字,每一位数字逐位替换为星号。def refun(repl): if len(repl.group()) == 11: return '[隐藏手机号]' else: return '*' * len(repl.group())re.sub('\d+', refun, 'moblie18217052373num123')'moblie[隐藏手机号]num***'

 

2)subn

描述:函数与 re.sub函数 功能一致,只不过返回一个元组 (字符串, 替换次数)。

语法:re.subn(pattern, repl, string, count=0, flags=0)

参数:同re.sub

re.subn('\d+','*','aaa34bvsa56s')#连续数字替换('aaa*bvsa*s', 2)
re.subn('\d','*','aaa34bvsa56s')#每个数字都替换一次('aaa**bvsa**s', 4)
text = 'chi13putao14butu520putaopi666'pattern = r'\d+'re.subn(pattern,'...',text)('chi...putao...butu...putaopi...', 4)


五、编译正则对象

描述:将正则表达式的样式编译为一个正则表达式对象(正则对象),可以用于匹配

语法:re.compile(pattern, flags=0)

参数:

  • pattern:该参数表示正则中的模式字符串;

  • flags:可选参数,表示编译时用的匹配模式(如忽略大小写、多行模式等),数字形式,默认为0。

prog   = re.compile(pattern)result = prog.match(string)等价于result = re.match(pattern, string)

如果需要多次使用这个正则表达式的话,使用re.compile()和保存这个正则对象以便复用,可以让程序更加高效。


六、转义函数

re.escape(pattern) 可以转义正则表达式中具有特殊含义的字符,比如:. 或者 * re.escape(pattern) 看似非常好用省去了我们自己加转义,但是使用它很容易出现转义错误的问题,所以并不建议使用它转义,而建议大家自己手动转义!


七、缓存清除函数

re.purge()函数作用就是清除正则表达式缓存,清除后释放内存。

···  END  ···
往期精彩回顾




浏览 54
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报