文章目录
【总结】正则表达式(2022.05.05)
1. 正则表达式
1.1 认识正则
正则表达式:解决字符串问题的工具(让复杂的字符串问题变得简单的一个工具)
1.2 匹配类符号
- 普通字符 - 在正则表达式中表示这个符号本身,对用字符串中的字符的要求就是符号本身
# 要求字符串:总共有3个字符,第一个是'a',第二个是'b',第三个是'c'
result = fullmatch(r'abc', 'abc')
print(result)
result = fullmatch(r'abc', 'abd')
print(result) # None
- . - 匹配任意一个字符
# 要求字符串:总共有3个字符,第一个是a,最后一个是c,中间可以是任何符号
result = fullmatch(r'a.c', 'abc')
print(result)
- \d - 匹配一个任意数字
result = fullmatch(r'a\dc', 'a5c')
print(result)
- \s - 匹配任意一个空白字符
# 空白字符包括:空格、\n、\t、\r
result = fullmatch(r'\d\s\d', '4 5')
print(result) # <re.Match object; span=(0, 3), match='4 5'>
result = fullmatch(r'a\sb', 'a b')
print(result)
- \w - 匹配任意一个数字、字母、下划线、中文
result = fullmatch(r'a\wb', 'a_b')
print(result)
result = fullmatch(r'a\wb', 'abb')
print(result)
result = fullmatch(r'a\wb', 'a5b')
print(result)
result = fullmatch(r'a\wb', 'a你b')
print(result)
- \D,\S,\W - 与相应的反斜杠小写字母的功能是相反的
# D - 匹配任意一个非数字字符
# S - 匹配任意一个非空白字符
# W - 匹配任意一个非数字、字母、下划线、中文字符
result = fullmatch(r'a\Db', 'a5b')
print(result) # None
result = fullmatch(r'a\Sb', 'a b')
print(result) # None
result = fullmatch(r'a\Wb', 'a&b')
print(result)
- [字符集] - 匹配字符集中任意一个字符
"""
[多个普通符号] - 例如:[abc12], 在a、b、c、1、2五个符号中任意一个可以匹配
[包含\开头的特殊符号] - 例如:[mn\d]、[m\dn]...,要求是m或者是n或者任意一个数字
[字符1-字符2] - 例如:[a-z]、[A-Z]、[0-9]、[a-z0-9]、[a-zA-Z]、[\u4e00-\u9fa5]等 表示范围
注意:[]中如果-不在两个字符之间,就不能表示谁到谁,那他就是个普通符号
"""
result = fullmatch(r'1[xyz]2', '1y2')
print(result)
result = fullmatch(r'1[x-y]2', '1y2')
print(result)
result = fullmatch(r'1[xyzmn]2', '1n2')
print(result)
result = fullmatch(r'1[a-z][3-6]2', '1y52')
print(result)
result = fullmatch(r'1[\u4e00-\u9fa5\d]2', '1你2')
print(result)
- [^字符集] - 匹配不在字符集中的任意一个字符
result = fullmatch(r'1[^xyz]2', '1y2')
print(result) # None
result = fullmatch(r'1[^xyz]2', '1q2')
print(result) # <re.Match object; span=(0, 3), match='1q2'>
1.3 匹配次数
-
-
- 匹配0次或者多次(任意次数)
-
"""
a* - a出现任意次数
\d* - 任意多个\d -> 任意多个数字
[abc]* - 任意多个[abc] -> 任意多个(a或者b或者c)
"""
result = fullmatch(r'a*b','aaaaab')
print(result)
result = fullmatch(r'a*b','b')
print(result)
result = fullmatch(r'[a-z]*b','jzdhb')
print(result) # <re.Match object; span=(0, 5), match='jzdhb'>
-
-
- 匹配1次或者多次(至少1次)
-
result = fullmatch(r'a+b','b')
print(result) # None
result = fullmatch(r'a+b','ab')
print(result)
- ? - 0次或1次
result = fullmatch(r'a?b','b')
print(result)
result = fullmatch(r'a?b','ab')
print(result)
result = fullmatch(r'a?b','aab')
print(result) # None
result = fullmatch(r'[-+]?123','-123')
print(result)
- {}
代码 | 含义 |
---|---|
{n} | n次 |
{m,n} | m到n次 |
{m,} | 至少m次 |
{,n} | 最多n次 |
# * == {0,}
# + == {1,}
# ? == {0,1}
result = fullmatch(r'\d{3}abc','123abc')
print(result)
result = fullmatch(r'\d{2,5}abc','1243abc')
print(result)
result = fullmatch(r'\d{2,}abc','437654abc')
print(result)
- 贪婪和非贪婪
在匹配次数不确定的时候,匹配模式分为贪婪和非贪婪两种,默认是贪婪的。
匹配次数不确定:*、+、?、{m,n}、{m,}、{,n}
贪婪和非贪婪:次数不确定的情况下,对应的字符串在不同次数下有多中匹配结果,贪婪取最多次数对应的结果。(前提是匹配成功有多种情况)
贪婪:*、+、?、{m,n}、{m,}、{,n}
非贪婪:*?、+?、??、{m,n}?、{m,}?、{,n}?
result = fullmatch(r'\d+','4564563')
print(result) # <re.Match object; span=(0, 7), match='4564563'>
# search(正则表达式,字符串) - 在字符串中查找第一个满足正则表达式的子串
result = search(r'\d+','jrtykm4564563官方你还敢')
print(result) # <re.Match object; span=(6, 13), match='4564563'>
result = search(r'\d+?','jrtykm4564563官方你还敢')
print(result) # <re.Match object; span=(6, 7), match='4'>
html = '<body><span><p>你好吗</p><p>百度</p><body>'
result = search(r'<p>.*</p>',html)
print(result) # <re.Match object; span=(18, 37), match='<p>你好吗</p><p>百度</p>'>
result = search(r'<p>.*?</p>',html)
print(result) # <re.Match object; span=(18, 28), match='<p>你好吗</p>'>
1.4 分组和分支
- 分组 - ():
分组就是在正则中用括号将正则中的部分内容括起来就形成一个分组
整体操作:
# 匹配:两个字母两个数字的结构重复3次,'mn78jh56lm89'
# 普通匹配方法
result = fullmatch(r'[a-zA-Z]{2}\d\d[a-zA-Z]{2}\d\d[a-zA-Z]{2}\d\d','mn78jh56lm89')
print(result)
# 整体操作方法
result = fullmatch(r'([a-zA-Z]{2}\d\d){3}','mn78jh56lm89')
print(result)
重复:
# 匹配:'23abc23'、'59abc59' - 成功
# '23abc59' - 失败
result = fullmatch(r'(\d\d)abc\1','59abc56')
print(result) # None
result = fullmatch(r'(\d\d)abc\1','59abc59')
print(result)
result = fullmatch(r'(\d{3})([a-z]{2})-\2\1=\1{3}','597ab-ab597=597597597')
print(result)
捕获:
result = findall(r'\d\d','gvfhgvhj34健康的是否具备780.巴水电局改变5745452')
print(result) # ['34', '78', '57', '45', '45']
result = findall(r'[a-z]\d\d','gvfhgvhj34健康的是否具备780.巴水电局改变5745d452')
print(result) # ['j34', 'd45']
result = findall(r'[a-z](\d\d)','gvfhgvhj34健康的是否具备780.巴水电局改变5745d452')
print(result) # ['34', '45'] - 此处用了分组捕获,不会匹配字母
- 2.分支 - | :
正则1|正则2 - 先用正则1进行匹配,如果匹配成功就直接成功,如果匹配失败再用正则2进行匹配,如果匹配成功就直接成功,如果匹配失败就失败
# 匹配: abc后面是两个任意数字或者两个任意的大写字母, 'abc34'、'abcKJ'
result = fullmatch(r'abc\d\d|abc[A-Z]{2}','abcMN')
print(result)
result = fullmatch(r'abc(\d\d|[A-Z]{2})','abc23')
print(result)
1.5 检测类符号和转义字符
- 检测类符号
检测类符号不是匹配符号,不会要求某个位置必须是什么样的字符,而是用来检测某个位置是否符合相关要求
(1) \b - 检测是否是单词边界
单词边界 - 凡是可以用来将两个单词区分开的符号,例如:空白字符、标点符号、字符串开头、字符串结尾
result = findall(r'\d+', '5areegrweg576 58过热和纽 约地铁看hu,附近的hurt 325,346,五十一条 银河')
print(result) # ['5', '576', '58', '325', '346']
result = findall(r'\b\d+', '5areegrweg576 58过热和纽 约地铁看hu,附近的hurt 325,346,五十一条 银河')
print(result) # ['5', '58', '325', '346']
result = findall(r'\b\d+\b', '5areegrweg576 58过热和纽 约地铁看hu,附近的hurt 325,346,五十一条 银河')
print(result) # ['325', '346']
(2) \B - 检测是否是非单词边界
(3) ^ - 检测是否是特定字符串开头([]外面)
(4) $ - 检测是否是特定字符串结尾
- 转义符号
result = fullmatch(r'\d\d\+\d\d','44+59')
print(result)
result = fullmatch(r'\([\u4e00-\u9fa5]{2}\)','(和第)')
print(result)
# 补充:独立存在有特殊意义的符号,放到[]中特殊功能会直接消失变成一个普通符号,例如:+、*、.、?、)、(等
result = fullmatch(r'[.+*?$]ab\.c','+ab.c')
print(result)
2. Python中的re模块
re模块是python用来支持正则表达式的一个模块
re模块中提供了各种和正则相关的函数:fullmatch、search、findall、split、sub等
2.1 常用的函数
- re.fullmatch(正则,字符串) - 判断整个字符串是否能够和正则表达式匹配,如果匹配成功返回匹配对象,匹配失败返回None
result = re.fullmatch(r'\d{3}', '718')
print(result) # <re.Match object; span=(0, 3), match='718'>
- re.match(正则,字符串) - 匹配字符串开头,如果匹配成功返回匹配对象,匹配失败返回None
result = re.match(r'\d{3}', '718VHFVHv脚后跟v拒绝后')
print(result) # <re.Match object; span=(0, 3), match='718'>
- re.search(正则,字符串) - 匹配字符串中第一个满足正则的字串,如果匹配成功返回匹配对象,匹配失败返回None
result = re.search(r'\d{3}', 'sdhgfs啊718大哥v方式718 三个电话给')
print(result) # <re.Match object; span=(7, 10), match='718'>
- re.findall(正则,字符串) - 获取字符串中所有满足正则的字符串,返回值是列表,列表中的元素是匹配到的字符串,若没有返回空列表
result = re.findall(r'\d{3}', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(result) # ['678', '718', '564']
result = re.findall(r'[a-z]\d{3}', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(result) # ['s678', 'g564']
result = re.findall(r'[a-z](\d{3})', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(result) # ['678', '564']
result = re.findall(r'([a-z])(\d{3})', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(result) # [('s', '678'), ('g', '564')]
- re.finditer(正则,字符串) - 获取字符串中所有满足正则的字符串,返回一个迭代器,迭代器中的元素是匹配对象
result = re.finditer(r'\d{3}', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(list(result))
result = re.finditer(r'([a-z])(\d{3})', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(list(result))
- re.split(正则,字符串) - 将字符串中所有满足正则的字串作为切割点对字符串进行切割,返回一个列表,例表中的元素是字符串
# re.split(正则,字符串, N) - 切割前N个切割点内容
result = re.split(r'\d{3}', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(result) # ['sdhgfs', '啊大哥v方式', ' 三个g', '电话给']
- re.sub(正则,字符串1, 字符串2) - 将字符串2中所有满足正则的字串全部替换成字符串1
message = '更舒服a海军第三共和b发v但是'
# 将字符串中abc都替换成++
result = re.sub(r'[abc]', '++', message)
print(result) # 更舒服++海军第三共和++发v但是
result = re.sub(r'\d+','0', 'sdhgfs678啊大哥v方式718 三个g564电话给')
print(result) # sdhgfs0啊大哥v方式0 三个g0电话给
2.2 匹配对象
result = re.search(r'(\d{3})-([A-Z]{2})','方式718-SD 三个g564电话给')
print(result) # <re.Match object; span=(2, 8), match='718-SD'>
# 1)获取匹配结果对应的字符串
# a.获取整个正则匹配到的字符串:匹配对象group()
r1 = result.group()
print(r1) # 718-SD
# b.获取某个分组匹配到的结果:匹配对象group(N)
r2 = result.group(1)
print(r2) # 718
r3 = result.group(2)
print(r3) # SD
# 2)获取匹配结果在原字符传中的位置信息
r1 = result.span()
print(r1) # (2, 8)
r2 = result.span(2)
print(r2) # (6, 8)
2.3 参数
- 单行匹配和多行匹配
多行匹配的时候.不能和’\n’进行匹配(默认): flags=re.M、(?m)
单行匹配的时候.可以和’\n’进行匹配:flags=re.S、(?s)
# 设置单行匹配
result = re.fullmatch('a.c', 'a\nc',flags=re.S)
print(result) # <re.Match object; span=(0, 3), match='a\nc'>
result = re.fullmatch('(?s)a.c', 'a\nc')
print(result) # <re.Match object; span=(0, 3), match='a\nc'>
- 忽略大小写
默认情况下大写字母和小写字母是不能匹配的,忽略大小写之后大写字母就可以和对应的小写字母匹配
方法:flags=re.I、(?i)
result = re.fullmatch('abc', 'aBc', flags=re.I)
print(result) # <re.Match object; span=(0, 3), match='aBc'>
result = re.fullmatch('(?i)12[a-z]', '12N')
print(result) # <re.Match object; span=(0, 3), match='12N'>
- 既要忽略大小写又要单行匹配
方法:flags=re.I|re.S、(?is)
result = re.fullmatch('abc.12', 'aBc\n12',flags=re.I|re.S)
print(result) # <re.Match object; span=(0, 6), match='aBc\n12'>
result = re.fullmatch('(?is)abc.12', 'aBc\n12',flags=re.I|re.S)
print(result) # <re.Match object; span=(0, 6), match='aBc\n12'>
result = re.fullmatch('(?i)12[a-z]', '12N')
print(result) # <re.Match object; span=(0, 3), match='12N'>
- 既要忽略大小写又要单行匹配
方法:flags=re.I|re.S、(?is)
result = re.fullmatch('abc.12', 'aBc\n12',flags=re.I|re.S)
print(result) # <re.Match object; span=(0, 6), match='aBc\n12'>
result = re.fullmatch('(?is)abc.12', 'aBc\n12',flags=re.I|re.S)
print(result) # <re.Match object; span=(0, 6), match='aBc\n12'>