正则表达式
本文主要讲的是正则表达式在python中的简单使用,只介绍关键的几个方法函数,就不赘述正则表达式的基础知识了。在我个人的工作学习生活场景中,正则表达式主要用在清洗数据、路由代码、判断用户输入字段是否合规等场景,很简单,拆开来说,无非就下面这些常见的使用场景,使用的函数也就那几个,其他现学现卖就好了。
从我的角度来说,re.search() 是使用最多的,结合分组、命名等使用方式写个匹配规则,然后search一下,提取目标字段。然后就是标识符需要好好看看,很多时候感觉表达式对了,但是就是匹配不到,很可能是因为标识符没设置,在你掌握了re.search() 和flags 后,已经能应付很多需求了,其他函数也自然就触类旁通,接下来开始正文。
re.match()和re.search()
SRE_Match object
为什么要把re.match()和re.search()放在一起说呢,因为它们两个返回的是同一种对象,官方描述是SRE_Match object ,其打印结果如下所示。
text = '<p>asdasdasaaa\nsdghaasdasdsdfs</p>kkkkkkkkkkkkk'
reg = r'<.*?>(?P<content>.*?)</.*?>'
res01 = re.match(pattern=reg, string=text, flags=re.S + re.M)
res02 = re.search(pattern=reg, string=text, flags=re.S + re.M)
print(res01)
print(res02)
print(type(res01))
print(type(res02))
<_sre.SRE_Match object; span=(0, 34), match='<p>asdasdasaaa\nsdghaasdasdsdfs</p>'>
<_sre.SRE_Match object; span=(0, 34), match='<p>asdasdasaaa\nsdghaasdasdsdfs</p>'>
<class '_sre.SRE_Match'>
<class '_sre.SRE_Match'>
这个search_match_obj中有几个常用的属性和方法
res = re.search(pattern=reg, string=text, flags=re.S)
res.group()
res.groups()
res.groupdict()
res.span()
re.match()
re.match()尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
函数语法:
re.match(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|
pattern | 匹配的正则表达式。 | string | 要匹配的字符串。 | flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志 |
匹配成功re.match()返回一个匹配的对象,否则返回None。可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
使用场景:例如检验用户输入的手机号是否合规、路由匹配等。
使用示例:
text = 'aa<p>asdasdasaaa\nsdghaasdasdsdfs</p>kkkkkkkkkkkkk'
reg = r'<.*?>(?P<content>.*?)</.*?>'
res = re.match(pattern=reg, string=text, flags=re.S + re.M)
print(res)
text = 'aa<p>asdasdasaaa\nsdghaasdasdsdfs</p>kkkkkkkkkkkkk'
reg = r'<.*?>(?P<content>.*?)</.*?>'
res = re.match(pattern=reg, string=text, flags=re.S + re.M)
print(res)
print(res.group())
print(res.groups())
print(res.groupdict())
打印结果如下:
<_sre.SRE_Match object; span=(0, 34), match='<p>asdasdasaaa\nsdghaasdasdsdfs</p>'>
<p>asdasdasaaa
sdghaasdasdsdfs</p>
('asdasdasaaa\nsdghaasdasdsdfs', 'p')
{'content': 'asdasdasaaa\nsdghaasdasdsdfs'}
(0, 34)
re.search()(重点)
re.search 扫描整个字符串并返回第一个成功的匹配。
函数语法:
re.search(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|
pattern | 匹配的正则表达式 | string | 要匹配的字符串。 | flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
匹配成功re.search()返回一个匹配的对象,否则返回None。可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
使用场景:例如检验用户输入的手机号是否合规、路由匹配等。
使用示例:多用在寻找目标字段,提取、清洗数据。
import re
text = '<p>asdasdasaaa\nsdghaasdasdsdfs</p>kkkkkkkkkkkkk'
reg = r'<.*?>(?P<content>.*?)</.*?>'
res = re.search(pattern=reg, string=text, flags=re.S + re.M)
print(res)
print(res.group())
print(res.groups())
print(res.groupdict())
<_sre.SRE_Match object; span=(0, 34), match='<p>asdasdasaaa\nsdghaasdasdsdfs</p>'>
<p>asdasdasaaa
sdghaasdasdsdfs</p>
('asdasdasaaa\nsdghaasdasdsdfs',)
{'content': 'asdasdasaaa\nsdghaasdasdsdfs'}
分组的意义,就是在匹配成功的字符串中,再提取()里面的字符串,re.search中通过groupdict() 拿到分组对应的内容。
re.flags
前文中,关于flags的使用如下:
res = re.search(pattern=reg, string=text, flags=re.S + re.M)
re.S + re.M 代表同时使用两种模式,re.S主要是为了让.匹配到\n,而re.M则是为了避免因为有\n而导致的换行匹配不成功,下面将对各个标识符的模式简要介绍一下,需要了解具体说明的看客还请移步官网等教程。
小结
标志位总共有9个常量,其中:
- 常用:IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE
- 几乎不用:LOCALE、UNICODE、TEMPLATE、DEBUG
re.sub()
该函数用于将匹配到字符串替换成目标字符。
语法:
re.sub(pattern, repl, string, count=0, flags=0)
参数:
- pattern : 正则中的模式字符串。
- repl : 替换的字符串,也可为一个函数。
- string : 要被查找替换的原始字符串。
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
示例:
text = 'aa<p>asdasdasaaa\nsdghaasdasdsdfs</p>kkkkkkkkkkkkk'
reg = r'<.*?>'
res = re.sub(pattern=reg, string=text, flags=re.S + re.M, repl=' ')
print(res)
aa asdasdasaaa
sdghaasdasdsdfs kkkkkkkkkkkkk
re.subn(pattern, repl, string, count=0, flags=0) 函数与 re.sub函数 功能一致,只不过返回一个元组 (字符串, 替换次数)。
re.split()
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
re.split(pattern, string, maxsplit=0, flags=0)
参数:
参数 | 描述 |
---|
pattern | 匹配的正则表达式 | string | 要匹配的字符串 | maxsplit | 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。 | flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志 |
示例
text = 'aa<p>asdasdasaaa\nsdghaasdasdsdfs</p>kkkkkkkkkkkkk'
reg = r'<.*?>'
res = re.split(pattern=reg, string=text, flags=re.S + re.M)
print(res)
re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。
语法格式为:
re.findall(pattern, string, flags=0)
参数:
- string : 待匹配的字符串。
- pos : 可选参数,指定字符串的起始位置,默认为 0。
- endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。
使用场景:多用于找到所有目标字段。
实例
str = 'aabbabaabbaa'
print(re.findall(r'a.b',str))
print(re.findall(r'a*b',str))
print(re.findall(r'a.*b',str))
print(re.findall(r'a.*?b',str))
print(re.findall(r'a(.*?)b',str))
str = '''aabbab
aabbaa
bb'''
print(re.findall(r'a.*?b',str))
print(re.findall(r'a.*?b',str,re.S))
re.finditer(pattern, string, flags=0 用法与re.findall() 差不多,但是前者返回的是迭代器,需要对其进行遍历,才能获取数据,后者则直接是个列表,为什么这么设计呢?这里我本人暂时也不清楚,貌似是因为使用finditer时,无需手动将整个正则用()括起来group()代表整个正则的匹配,这里的需求场景比较特殊,后面若深挖,我将继续分享。
re.fullmatch()
re.fullmatch()的返回值re.match()和re.search()一样都是一个SRE_Match object,fullmatch是完全匹配(从字符串开头到结尾),而match()只是从头匹配,但从理论上来说,能用fullmatch实现的,用match也都能实现。
即,fullmatch(pattern, string, flags=0) ,是match函数的完全匹配(从字符串开头到结尾)版本。
示例:
qq = '1234567890'
res01 = re.fullmatch(r'[1-9]\d{4,11}', qq)
res02 = re.match(r'^[1-9]\d{4,11}$', qq)
print(res01)
print(res02)
re.compile()
在Python中使用正则表达式时,re模块内部会干两件事情:
那么如果一个正则表达式要重复使用几千次,出于效率的考虑,应该先把这个正则先预编译好,接下来重复使用时就不再需要编译这个步骤了,直接匹配,提高我们的效率。
re.compile(pattern, flags=0) 接受pattern和flags两个参数,使用简单示例如下:
re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
A = re_telephone.match('010-12345').groups()
print(A)
B = re_telephone.match('010-8086').groups()
print(B)
小结
方法分类
查找一个匹配项
-
re.search() -
re.match() -
re.fullmatch()
查找多个匹配项
-
re.findall() -
re.finditer()
替换
分割
编译
注意细节
-
字节串 与 字符串 模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字节串 (bytes)。 但是,Unicode 字符串与8位字节串不能混用。 -
反斜杠和r 的使用 正则表达式使用反斜杠/ 来表示特殊形式,或者把特殊字符转义成普通字符。反斜杠在普通的 Python 字符串里也有相同的作用,所以就产生了冲突。解决办法是对于正则表达式样式使用 Python 的原始字符串表示法;在带有 ‘r’ 前缀的字符串字面值中,反斜杠不必做任何特殊处理。 -
重复使用某个正则 如果要重复使用某个正则表达式,可使用re.compile() 优化。
正则表达式网站
参考资料
https://zhuanlan.zhihu.com/p/127807805
https://www.runoob.com/python/python-reg-expressions.html
https://regexr.com/
https://regexone.com/
|