一、正则表达式
1. 什么是正则表达式
正则表达式是处理字符串的工具,通过不同的正则符号来描述字符串的规则
2. 正则符号(正则表达式的语法)
1) 普通字符(普通字符代表字符本身)
除了在正则中有特殊功能和特殊意义的符号以外的字符都是普通字符
# 匹配一个字符串有三个字符,分别是'a', 'b', 'c'
re_str = 'abc'
result = fullmatch(re_str, 'abc')
print(result) # <_sre.SRE_Match object; span=(0, 3), match='abc'>
2) .
匹配任意一个字符, 一个.
只能匹配一个字符
# 匹配一个字符串长度是8,前三个字符是abc,后三个字符是123,中间任意两个字符
re_str = r'abc..123'
result = fullmatch(re_str, 'abc-+123')
print(result) # <_sre.SRE_Match object; span=(0, 8), match='abc-+123'>
3) \w
匹配一个数字、字母或者_(在ASCII码表中), 一个\w
只能匹配一个字符
# 匹配一个长度是4的字符串,第一个字符是数字、字母或者_,后三个字符是abc
re_str = r'\wabc'
result = fullmatch(re_str, '_abc')
print(result) # <_sre.SRE_Match object; span=(0, 4), match='_abc'>
4) \d
匹配任意一个数字字符, 一个\d
只能匹配一个字符
# 匹配一个长度是5的字符串,前两个字符是任意数字,后面三个是任意字符
re_str = r'\d\d...'
result = fullmatch(re_str, '12sfa')
print(result) # <_sre.SRE_Match object; span=(0, 5), match='12sfa'>
5) \s
匹配任意一个空白字符, 一个\s
只能匹配一个字符
空白字符包括空格,换行符,制表符等
result = fullmatch(r'how\sare!', 'how are!')
print(result) # <_sre.SRE_Match object; span=(0, 8), match='how are!'>
6) \大写字母
\D
匹配除了数字字符以外的任意字符(匹配一个非数字字符)
\S
匹配一个非空白字符
re_str = r'\Dabc\S'
print(fullmatch(re_str, '+abc1')) # <_sre.SRE_Match object; span=(0, 5), match='+abc1'>
7) [字符集]
匹配字符集中出现的任意一个字符
注意
:一个[]
只能匹配一个字符
a.
[abc]
匹配abc中任意一个字符
# 匹配一个长度是4的字符串,第一个字符是1或3或7,后三个字符是abc
re_str = r'[137]abc'
print(fullmatch(re_str, '1abc')) # <_sre.SRE_Match object; span=(0, 4), match='1abc'>
print(fullmatch(re_str, '2abc')) # None
b.
[1-9]
匹配1~9中的任意一个字符(字符编码值递增)
[a-z
] 匹配任意一个小写字母
[A-Z]
匹配任意一个大写字母
[a-zA-Z]
匹配任意一个字母
[a-zA-Z\d_]
匹配任意一个字母、数字或_
[ \t\n]
匹配任意一个空白字符
[\u4e00-\u9fa5]
匹配任意一个中文字符
re_str = r'[!-&]123'
print(fullmatch(re_str, '$123')) # <_sre.SRE_Match object; span=(0, 4), match='$123'>
print(fullmatch(re_str, '(123')) # None
re_str = r'[a-zA-Z\d_]==='
print(fullmatch(re_str, '1===')) # <_sre.SRE_Match object; span=(0, 4), match='1==='>
print(fullmatch(re_str, 'W===')) # <_sre.SRE_Match object; span=(0, 4), match='W==='>
# print(fullmatch(r'[z-a]', 'a')) # sre_constants.error: bad character range z-a at position 1
8) [^字符集]
匹配不在字符集中的任意一个字符
[^abc]
匹配任意一个不是a,b,c的字符
[^2-8]
匹配任意一个不是数字2-8的字符
[^\u4e00-\u9fa5]
匹配任意一个非中文字符
re_str = r'[^2-8]abc'
print(fullmatch(re_str, '0abc')) # <_sre.SRE_Match object; span=(0, 4), match='0abc'>
print(fullmatch(re_str, '5abc')) # None
2. 检测符号
所有的检测符号都不会影响字符串的长度
1) \b
:检查是否是单词边界
单词边界指的是能够将两个单词隔开并且不会产生歧义的任意符号(空白字符、标点符号、字符串开头和字符串结尾)
匹配规则: 先去掉\b
对字符串进行匹配,如果匹配成功再检查\b所在的位置是否是单词边界
# 匹配一个长度为6的字符串,每个字符分别是a,b,c,1,2,3,并且要求abc和123之间是单词边界
re_str = r'abc\b123'
print(fullmatch(re_str, 'abc123')) # None
re_str = r'abc\b,123'
print(fullmatch(re_str, 'abc,123')) # <_sre.SRE_Match object; span=(0, 7), match='abc,123'>
print(search(r'\d\d', 'sf86sfs 67 =--')) # <_sre.SRE_Match object; span=(2, 4), match='86'>
print(search(r'\b\d\d\b', 'sf86sfs 67 =--')) # <_sre.SRE_Match object; span=(8, 10), match='67'>
2) ^
:检查^
所在的位置是否是字符串开头
注意
:这里的^
要在[]
外面
re_str = r'^\d\d\d'
print(fullmatch(re_str, '345')) # <_sre.SRE_Match object; span=(0, 3), match='345'>
print(search(re_str, 'dasfa345sdh982==654==')) # None
print(findall(re_str, '345sdh982==654==')) # ['345']
print(search(r'^\d\d\d', '345')) # <_sre.SRE_Match object; span=(0, 3), match='345'>
3) $
:检查$
所在的位置是否是字符串结尾
re_str = r'\d\d\d$'
print(fullmatch(re_str, '345')) # <_sre.SRE_Match object; span=(0, 3), match='345'>
print(search(re_str, 'dasfa345sdh982==654==124')) # <_sre.SRE_Match object; span=(21, 24), match='124'>
print(findall(re_str, '345sdh982==654==123')) # ['123']
3. 控制次数的符号
1) *
匹配0次或多次
123a*
123后面a出现0次或多次(123,123a,123aa)
123\d*
123后面出现0个或者多个任意数字字符(123,1230,12311)
123[mnxy9]*
123,123m,123mmn,12399
re_str = r'abc0*123'
print(fullmatch(re_str, 'abc00123')) # <_sre.SRE_Match object; span=(0, 8), match='abc00123'>
2) +
匹配1次或多次
123a+ 匹配123a,123aa,123aaa...
re_str = r'123[a-z]+'
print(fullmatch(re_str, '123iyujh')) # <_sre.SRE_Match object; span=(0, 8), match='123iyujh'>
3) ?
匹配0次或1次
-?123 匹配123/-123
re_str = r'_?abc'
print(fullmatch(re_str, 'abc')) # <_sre.SRE_Match object; span=(0, 3), match='abc'>
print(fullmatch(re_str, '_abc')) # <_sre.SRE_Match object; span=(0, 4), match='_abc'>
4) {}
{N}
匹配N次a{3} 匹配3个a
\d{3} 匹配任意3个数字,345,344,000...
{M, N}
匹配M~N次(至少M次,至多N次)
{M,}
匹配至少M次
{, N}
匹配至多N次
# 匹配电话号码
re_str = r'1[3-9]\d{9}'
# 匹配密码,要求是6-12位的数字或者字母
re_str = r'[a-zA-Z\d]{6,12}'
print(fullmatch(r'123a{2,4}', '123aa')) # <_sre.SRE_Match object; span=(0, 5), match='123aa'>
print(fullmatch(r'123a{2,4}', '123a')) # None
5) 贪婪和非贪婪
在匹配次数不确定时,会出现贪婪和非贪婪两种情况:默认情况都是贪婪
贪婪:在能够匹配成功的情况下,匹配次数尽可能多
非贪婪:在能够匹配成功的情况下,匹配次数尽可能少(在匹配次数后加?
)
re_str = r'a.+'
print(search(re_str, 'hsjsa==2-32')) # <_sre.SRE_Match object; span=(4, 11), match='a==2-32'>
print(search(r'a.+?', 'hsjsa==2-32')) # <_sre.SRE_Match object; span=(4, 6), match='a='>
re_str = r'a.+b'
print(search(re_str, 'a234b123b123')) # <_sre.SRE_Match object; span=(0, 9), match='a234b123b'>
re_str = r'a.+?b'
print(search(re_str, 'a234b123b123')) # <_sre.SRE_Match object; span=(0, 5), match='a234b'>
4. 分支和分组
1) |
分支
正则1|
正则2 : 先让正则1匹配,如果匹配成功就成功,匹配失败再让正则2匹配(正则1和正则2中只要有一个能匹配成功即可)
re_str = r'abc|123'
print(fullmatch(re_str, 'abc')) # <_sre.SRE_Match object; span=(0, 3), match='abc'>
print(fullmatch(re_str, '123')) # <_sre.SRE_Match object; span=(0, 3), match='123'>
re_str = r'\d{2,5}|[a-z]+123'
print(fullmatch(re_str, '2141')) # <_sre.SRE_Match object; span=(0, 4), match='2141'>
print(fullmatch(re_str, 'a123')) # <_sre.SRE_Match object; span=(0, 4), match='a123'>
练习1:写一个正则表达式,要求匹配一个字符串:abc的前面是两个数字或者两个大写字母
# 方法1
re_str = r'\d{2}abc|[A-Z]{2}abc'
print(fullmatch(re_str, '41abc')) # <_sre.SRE_Match object; span=(0, 5), match='41abc'>
print(fullmatch(re_str, 'QWabc')) # <_sre.SRE_Match object; span=(0, 5), match='QWabc'>
2)()
分组: 将()中的内容作为一个整体
a. 整体操作
r'(\d|[A-Z]){2}abc' : 匹配一个字符串,后面是abc,前面是两个数字或者两个大写字母
r'([a-zA-Z]\d){3}' : 字母数字重复3次
b. 分组
分组截取:方面后面分段或者分情况取不同的匹配结果
re_str = r'(\d{3})[a-z]{3}'
print(fullmatch(re_str, '344hsj')) # <_sre.SRE_Match object; span=(0, 6), match='344hsj'>
print(findall(re_str, 'sdf345赛风weg568lkjoik==789wer--899fdsf')) # ['568', '789', '899']
分组重复:在正则中用\X重复第X个分组匹配到的内容
re_str = r'(\d{3})[a-z]{3}\1'
print(fullmatch(re_str, '123abc123')) # <_sre.SRE_Match object; span=(0, 9), match='123abc123'>
print(fullmatch(re_str, '123abc122')) # None
re_str = r'(\d{3})([a-z]{3})\2'
print(fullmatch(re_str, '123abcsaf')) # None
print(fullmatch(re_str, '123abcabc')) # <_sre.SRE_Match object; span=(0, 9), match='123abcabc'>
注意
:\X的前面必须有这个分组
5. 转义符号
1) 加\
在正则中有特殊功能和特殊意义的符号前加\
,让这个符号的特殊功能和意义消失
re_str = r'\d{3}\.[a-z]{3}'
print(fullmatch(re_str, '111.abc')) # <_sre.SRE_Match object; span=(0, 7), match='111.abc'>
print(fullmatch(re_str, '111=abc')) # None
re_str = r'a\+\d{3}'
print(fullmatch(re_str, 'a+123')) # <_sre.SRE_Match object; span=(0, 5), match='a+123'>
print(fullmatch(re_str, 'a0123')) # None
2) 加[]
在[]
中有特殊意义的符号: a. ^
放在最开头; b. -
放在两个字符中间
其它符号包括:.
,+
,?
,*
,$
这些单独的符号在[]
中都表示这个符号本身
re_str = r'\d{3}[.][a-z]{3}'
print(fullmatch(re_str, '123.ada')) # <_sre.SRE_Match object; span=(0, 7), match='123.ada'>
print(fullmatch(re_str, '123_ada')) # None
二、re模块
re模块是python提供的,专门针对正则表达式应用的相关函数
1. compile(正则表达式) : 将正则表达式转换成正则对象
re_obj = compile(r'\d{3}')
fullmatch(r'\d{3}', '347')
re_obj.fullmatch('347')
2.字符串匹配
fullmatch(正则表达式, 字符串) : 让正则表达式和字符串完全匹配
match(正则表达式, 字符串) : 匹配字符串开头
以上两个方法的结果:匹配失败结果是None, 匹配成功会返回匹配对象
re_str = '\d{3}'
print(fullmatch(re_str, '783sdfs')) # None
print(match(re_str, '783sdfs')) # <_sre.SRE_Match object; span=(0, 3), match='783'>
1) 匹配对象
a. 获取匹配到的字符串
匹配对象.group() : 获取整个正则表达式匹配到的字符串,结果是字符串
匹配对象.group(N) : 获取整个正则表达式中第N个分组匹配到的字符串
result = fullmatch(r'(\d{3})=([a-z]{2})', '234=am')
print(result) # <_sre.SRE_Match object; span=(0, 6), match='234=am'>
print(result.group()) # 234=am
print(result.group(1)) # 234
print(result.group(2)) # am
b. 获取匹配到的字符串在原字符串中的位置信息
匹配对象.span() : 返回匹配结果在原字符串中的下标范围[开始下标, 结束下标)
匹配对象.span(N) : 返回第N个分组的匹配结果在原字符串中的下标范围[开始下标, 结束下标)
print(result.span()) # (0, 6)
print(result.span(2)) # (4, 6)
c. 获取原字符串
匹配对象.string
print(result.string) # 234=am
3. 查找
1)search(正则表达式, 字符串)
在字符串中查找第一个满足正则表达式的子串,如果找到结果是匹配对象,否则是None
result = search(r'\d{3}', '324ggs+++325hsdf')
print(result) # <_sre.SRE_Match object; span=(0, 3), match='324'>
2)findall(正则表达式, 字符串)
获取字符串中所有满足正则表达式的子串;返回值是一个列表
result = findall(r'\d{3}[a-z]{2}', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
print(result) # ['234hu', '345mm', '348jl']
result = findall(r'(\d{3})[a-z]{2}', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
print(result) # ['234', '345', '348']
result = findall(r'(\d{3})([a-z]{2})', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
print(result) # [('234', 'hu'), ('345', 'mm'), ('348', 'jl')]
注意
:如果正则表达式中有分组,列表中的匹配结果只会取分组匹配到的内容
3)finditer(正则表达式, 字符串)
获取字符串中所有满足正则表达式的子串;返回值是一个迭代器,元素是匹配对象
result = finditer(r'(\d{3})([a-z]{2})', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
group = []
group1 = []
group2 = []
for x in result:
group.append(x.group())
group1.append(x.group(1))
group2.append(x.group(2))
print(group, group1, group2) # ['234hu', '345mm', '348jl'] ['234', '345', '348'] ['hu', 'mm', 'jl']
4. 切割
split(正则表达式, 字符串)
将字符串中满足正则表达式的子串作为切割点,对字符串进行切割;返回一个字符串列表
result = split(r'\d+', '多棱镜3ja89撒扥撒899SDS')
print(result) # ['多棱镜', 'ja', '撒扥撒', 'SDS']
5. 替换
sub(正则表达式, 字符串1, 字符串2)
将字符串2中所有满足正则表达式的子串都替换成字符串1;返回一个字符串
message = 'abc9023'
new_message = sub(r'[b]|[0]', '*', message)
print(new_message) # a*c9*23