Day16正则表达式总结
认识正则表达式
作用:解决字符串问题的工具(让复杂的字符串问题变得简单的一个工具)
# 方法1
def is_tel_num(tel_no: str):
if len(tel_no) != 11:
return False
if tel_no[0] != '1':
return False
if tel_no[1] not in '3456789':
return False
return tel_no.isdigit()
tel = '13354627381'
print(is_tel_num(tel))
from re import fullmatch,findall
# 方法2:
def is_tel_num2(tel_no: str):
return fullmatch(r'1[3-9]\d{9}', tel_no) != None
tel = '13354622381'
print(is_tel_num2(tel))
message = '收到回复就234数据jssh 78师傅好看2391金虎送福23刷卡机sshs34'
# 234、78、2391、23、34
# 方法1:
all_num = []
num_str = ''
for index in range(len(message)):
if message[index].isdigit():
num_str += message[index]
else:
all_num.append(num_str)
num_str = ''
all_num.append(num_str)
all_num = [int(x) for x in all_num if x]
print(all_num)
# 方法2:
message = '收到回复就234数据jssh 78师傅好看2391金虎送福23刷卡机sshs34'
all_num2 = findall(r'\d+', message)
print(all_num2)
re模块
re模块是python用来支持正则表达式的一个模块
re模块中提供了各种和正则相关的函数:fullmatch、search、findall、match、split、sub等等
fullmatch(正则表达式, 字符串) - 判断整个字符串是否完全符号正则表达式描述的规则。如果不符合返回值是None
python中提供正则表达式的方式:r'正则表达式'
js中提供正则表达式的方式:/正则表达式/
# 1. 常用的函数
"""
1)re.fullmatch(正则, 字符串) - 用整个字符串和正则表达式进行匹配,如果匹配成功返回匹配对象,匹配失败返回None
2)re.match(正则, 字符串) - 匹配字符串开头,如果匹配成功返回匹配对象,匹配失败返回None
3)re.search(正则, 字符串) - 匹配字符串中第一个满足正则的字串,如果匹配成功返回匹配对象,匹配失败返回None
4)re.findall(正则, 字符串) - 获取字符串中所有满足正则的子串,返回值是列表,列表中的元素是匹配到的字符串
5)re.finditer(正则, 字符串) - 获取字符串中所有满足正则的子串,返回一个迭代器,迭代器中的元素是匹配对象
6)re.split(正则, 字符串) - 将字符串中所有满足正则的字串作为切割点对字符串进行切割,返回一个列表,列表中的元素是字符串
7)re.sub(正则, 字符串1, 字符串2) - 将字符串2中所有满足正则的字串全部替换成字符串1
"""
# 1)re.fullmatch(正则, 字符串) - 用整个字符串和正则表达式进行匹配,如果匹配成功返回匹配对象,匹配失败返回None
result = re.fullmatch(r'\d{3}', '728')
print(result)
# 2)re.match(正则, 字符串) - 匹配字符串开头,如果匹配成功返回匹配对象,匹配失败返回None
result = re.match(r'\d{3}', '728会计师大会的咖啡机')
print(result)
# 3)re.search(正则, 字符串) - 匹配字符串中第一个满足正则的字串,如果匹配成功返回匹配对象,匹配失败返回None
result = re.search(r'\d{3}', '手机号728会计师大262会的咖啡机')
print(result)
# 4)re.findall(正则, 字符串) - 获取字符串中所有满足正则的子串,返回值是列表,列表中的元素是匹配到的字符串
result = re.findall(r'\d{3}', '手机号728会计师大262会的咖0923啡机')
print(result) # ['728', '262', '092']
result = re.findall(r'[a-z]\d{3}', '手机号728会计师大m262会的咖0923啡k7823机')
print(result) # ['m262', 'k782']
result = re.findall(r'[a-z](\d{3})', '手机号728会计师大m262会的咖0923啡k7823机')
print(result) # ['262', '782']
result = re.findall(r'([a-z])(\d{3})', '手机号728会计师大m262会的咖0923啡k7823机')
print(result) # [('m', '262'), ('k', '782')]
# 5)re.finditer(正则, 字符串) - 获取字符串中所有满足正则的子串,返回一个迭代器,迭代器中的元素是匹配对象
result = re.finditer(r'\d{3}', '手机号728会计师大262会的咖0923啡机')
print(list(result))
result = re.finditer(r'([a-z])(\d{3})', '手机号728会计师大m262会的咖0923啡k7823机')
print(list(result))
# 6)
# re.split(正则, 字符串) - 将字符串中所有满足正则的字串作为切割点对字符串进行切割,返回一个列表,列表中的元素是字符串
# re.split(正则, 字符串, N)
result = re.split(r'\d{3}', '手机号728会计师大m262会的咖0923啡k7823机')
print(result) # ['手机号', '会计师大m', '会的咖', '3啡k', '3机']
message = '安徽师a水电费b煽风点火可见a烧开后b顺丰科技c水电费即可'
result = re.split(r'[abc]', message)
print(result)
result = re.split(r'[abc]', message, 3)
print(result)
# 7)re.sub(正则, 字符串1, 字符串2) - 将字符串2中所有满足正则的字串全部替换成字符串1
# re.sub(正则, 字符串1, 字符串2, N)
message = '安徽师a水电费b煽风点火可见a烧开后b顺丰科技c水电费即可'
# 将a、b、c都替换成'++'
# new_message = message.replace('a', '++')
# new_message = new_message.replace('b', '++')
# new_message = new_message.replace('c', '++')
# print(new_message)
result = re.sub(r'[abc]', '++', message)
print(result)
result = re.sub(r'\d', '0', '手机号728会计师大m262会的咖0923啡k7823机')
print(result)
result = re.sub(r'\d', '0', '手机号728会计师大m262会的咖0923啡k7823机', 5)
print(result)
# 2. 匹配对象
result = re.search(r'([a-z]{2})-(\d{3})', '手机号ag-728会计师大262会的咖啡机')
print(result) # <re.Match object; span=(3, 9), match='ag-728'>
# 1)获取匹配结果对应的字符串
# a.获取整个正则匹配到的字符串: 匹配对象.group()
r1 = result.group()
print(r1) # 'ag-728'
# b.获取某个分组匹配到的结果: 匹配对象.group(N)
r2 = result.group(1)
print(r2) # 'ag'
r3 = result.group(2)
print(r3) # '728'
# 2)获取匹配结果在原字符串中的位置信息
r1 = result.span()
print(r1)
r2 = result.span(2)
print(r2)
# 3.参数
# 1)单行匹配和多行匹配
"""
多行匹配的时候.不能和'\n'进行匹配 (默认):flags=re.M、(?m)
单行匹配的时候.可以和'\n'进行匹配:flags=re.S、(?s)
"""
# 设置单行匹配
result = re.fullmatch(r'a.c', 'a\nc', flags=re.S)
print(result)
result = re.fullmatch(r'(?s)a.c', 'a\nc')
print(result)
# 2)忽略大小写
"""
默认情况下大写字母和小写字母是不能匹配,忽略大小写以后大写字母就可以和对应的小写字母匹配
方法:flags=re.I、(?i)
"""
result = re.fullmatch(r'abc', 'aBc', flags=re.I)
print(result)
result = re.fullmatch(r'(?i)12[a-z]', '12N')
print(result)
# 3)既忽略大小写又要单行匹配
# 方法:flags=re.I|re.S、(?si)
result = re.fullmatch(r'abc.12', 'aBc\n12', flags=re.I|re.S)
print(result)
result = re.fullmatch(r'(?si)abc.12', 'aBc\n12')
print(result)
匹配类符号
一个正则符号表示一类字符
# 匹配类符号在正则中的作用:用来要求字符串中某个位置必须是什么样的字符
# 1)普通符号 - 在正则表达式中表示这个符号本身,对应字符串中的字符的要求就是符号本身。
# 要求字符串:总共有3个字符,第一个是'a',第二个是'b',第三个是'c'
result = fullmatch(r'abc', 'abc')
print(result)
result = fullmatch(r'abc', 'mnd')
print(result)
# 2) . - 匹配一个任意字符
# 要求字符串:总共有3个字符,第一个是'a',最后一个是'c',中间可以是任何符号
result = fullmatch(r'a.c', 'a*c')
print(result)
result = fullmatch(r'..xy', '是sxy')
print(result)
# 3)\d - 匹配一个任意数字
result = fullmatch(r'a\dc', 'a2c')
print(result)
result = fullmatch(r'\d\d\d..', '823m是')
print(result)
# 4)\s - 匹配任意一个空白字符
# 空白字符包括:空格、\n、\t
result = fullmatch(r'a\sb', 'a b')
print(result)
# 5)\w - 匹配任意一个数字、字母或者下划线或者中文
result = fullmatch(r'a\wb', 'a3b')
print(result)
# 6)\大写字母 - 与相应的小写字母的功能相反
"""
\D - 匹配任意一个非数字字符
\S - 匹配任意一个非空白字符
\W
"""
result = fullmatch(r'a\Db', 'a2b')
print(result) # None
result = fullmatch(r'a\Db', 'a)b')
print(result)
# 7) [字符集] - 匹配字符集中任意一个字符
# 注意:一个[]只能匹配一个字符
"""
[多个普通符号] - 例如:[abc12], 在'a'、'b'、'c'、'1'、'2'五个符号中任意一个可以匹配
[包含\开头的特殊符号] - 例如:[mn\d]、[m\dn]、[\dmn], 要求是m或者n或者任意一个数字
[字符1-字符2] - 例如:[a-z],要求是任意一个小写字母
[a-zA-Z],要求是任意一个字母
[2-9a-z],要求是2到9或者是任意一个小写字母
[\u4e00-\u9fa5],要求是任意一个中文
[\u4e00-\u9fa5\dabc]
注意:[]中如果-不在两个字符之间,就不能表示谁到谁,那它就是个普通符号
"""
result = fullmatch(r'1[xyzmn]2', '1n2')
print(result)
result = fullmatch(r'a[mn\d]b', 'a9b')
print(result)
result = fullmatch(r'1[a-z][a-z]2', '1hm2')
print(result)
result = fullmatch(r'a[x\u4e00-\u9fa5\dy]b', 'ayb')
print(result)
result = fullmatch(r'1[-az]2', '1-2')
print(result)
# 8) [^字符集] - 匹配不在字符集中的任意一个字符
result = fullmatch(r'1[^xyz]2', '1x2')
print(result)
result = fullmatch(r'1[^\dab]2', '1M2')
print(result)
result = fullmatch(r'a[^2-9]b', 'a3b')
print(result)
匹配次数
# 1. * - 匹配0次或者多次(任意次数)
"""
a* - a出现任意次数
\d* - 任意多个\d -> 任意多个数字
[abc]* - 任意多个[abc] -> 任意多个(a或者b或者c)
...
"""
result = fullmatch(r'a*b', 'aaaaaaab')
print(result)
result = fullmatch(r'\d*b', '21222b')
print(result)
result = fullmatch(r'[A-Z]*b', 'KDBb')
print(result)
# 2. + - 匹配1次或者多次(至少1次)
result = fullmatch(r'a+b', 'aaaaab')
print(result)
# 3. ? - 0次或1次
result = fullmatch(r'-?123', '-123')
print(result)
result = fullmatch(r'[+-]?123', '+123')
print(result)
# 4. {}
"""
{N} - N次
{M,N} - M到N次
{M,} - 至少M次
{,N} - 最多N次
* == {0,}
+ == {1,}
? == {0,1}
"""
result = fullmatch(r'\d{3}abc', '623abc')
print(result)
result = fullmatch(r'\d{2,5}abc', '2234abc')
print(result)
# 5. 贪婪和非贪婪
# 在匹配次数不确定的时候,匹配模式分为贪婪和非贪婪两种,默认是贪婪的。
"""
匹配次数不确定:*、+、?、{M,N}、{M,}、{,N}
贪婪和非贪婪:在次数不确定的情况下,对应的字符串在不同次数下有多种匹配结果,贪婪取最多次数对应的结果。(前提是匹配成功有多种情况)
非贪婪取最少次数对应的结果。
贪婪:*、+、?、{M,N}、{M,}、{,N}
非贪婪:*?、+?、??、{M,N}?、{M,}?、{,N}?
"""
result = fullmatch(r'\d+?', '26373')
print(result) # '26373'
# search(正则表达式, 字符串) - 在字符串中查找第一个满足正则表达式的字串
# 2 -> 1 26 -> 2 263 -> 3 2637 -> 4 26373 -> 5
result = search(r'\d+?', '水电费国家26373sfdhgahj')
print(result)
# 'amnb' -> 2 'amnbxnxb' -> 6 'amnbxnxb盛世b' -> 9
result = search(r'a.*b', r'施工方回家啊amnbxnxb盛世b-2---==')
print(result) # 'amnbxnxb盛世b
result = search(r'a.*?b', r'施工方回家啊amnbxnxb盛世b-2---==')
print(result) # 'amnb'
# '<p>你是好吗</p>' - 4 '<p>你是好吗</p><a>百度</a><p>hello world!</p>'
html = '<body><span>开始!</span><p>你是好吗</p><a>百度</a><p>hello world!</p></body>'
result = search(r'<p>(.*?)</p>', html)
print(result, result.group(1))
result = search(r'a.+?c', '手机端发挥amnc你好c会计核算地方abc')
print(result)
分组和分支
# 1. 分组 - ()
# 分组就是在正则中用括号将正则中的部分内容括起来就形成了一个分组
# 1)整体操作
# 2) 重复
# 在正则中:\N可以重复\N所在的位置的前面的第N个分组匹配到的内容
# 3) 捕获 - 获取正则匹配结果中的部分内容
# 匹配:两个字母两个数字的结构重复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' - 成功
# '23abc56' - 失败
# result = fullmatch(r'\d\dabc\d\d', '23abc56')
# print(result)
result = fullmatch(r'(\d\d)abc\1', '23abc23')
print(result)
result = fullmatch(r'(\d{3})([a-z]{2})-\2\1=\1{3}', '876nm-nm876=876876876')
print(result)
result = fullmatch(r'(((\d{2})[A-Z]{3})([a-z]{2}))-\2-\1-\3', '34MNGbn-34MNG-34MNGbn-34')
print(result)
result = findall(r'[a-z]\d\d', '爱喝酒2空间数据78,明年and45没精神2341==hsn89=江=263')
print(result) # ['d45', 'n89']
result = findall(r'[a-z](\d\d)', '爱喝酒2空间数据78,明年and45没精神2341==hsn89=江=263')
print(result) # ['45', '89']
# 2. 分支 - |
# 正则1|正则2 - 先用正则1进行匹配如果匹配成功就直接成功,如果匹配失败再用正则2进行匹配,如果匹配成功就成功,如果失败就失败
# 匹配: abc后面是两个任意数字或者两个任意的大写字母, 'abc34'、'abcKJ'
result = fullmatch(r'abc\d\d|abc[A-Z]{2}', 'abc34')
print(result)
result = fullmatch(r'abc(\d\d|[A-Z]{2})', 'abcKL')
print(result)
检测类符号
# 检测类符号不是匹配符号,不会要求某个位置必须是什么样的字符,而是用检测某个位置是否符号相关要求
# 1)\b - 检测是否是单词边界
"""
单词边界 - 凡是可以用来将两个单词区分开的符号,例如:空白字符、标点符号、字符串开头、字符串结尾
"""
result = findall(r'\b\d+\b', '23数据2367skjj,89是2039,按键是否 768hsj,237 很久没79ssjs 89')
print(result)
# 2)\B - 检测是否是非单词边界
# 3)^ - 检测是否是字符串开头([]外面)
# 4)$ - 检测是否是字符串结尾
result = fullmatch(r'1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}', '13578237392')
print(result)
result = search(r'^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$', '13578237392')
print(result)
# ^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$
转义符号
正则中的转义符号是指在本身就具备特殊功能的符号前加\,让它本身具备的特殊功能消失变成一个普通符号。
# 写一个正则匹配一个小数: 2.3
result = fullmatch(r'\d\.\d', '2.3')
print(result)
# '23+78'
result = fullmatch(r'\d\d\+\d\d', '65+23')
print(result)
# '(护具)'
result = fullmatch(r'\([\u4e00-\u9fa5]{2}\)', '(护具)')
print(result)
# '\dabc'
result = fullmatch(r'\\dabc', '\dabc')
print(result)
# '-abc'、'Mabc'、'Nabc'
result = fullmatch(r'[mn\]]abc', ']abc')
print(result)
# 补充:独立存在有特殊意义的符号,放到[]中特殊功能会直接消失变成一个普通符号,例如:+、*、.、?、)、(等
result = fullmatch(r'[.+*?$]ab[.]c', '+ab.c')
print(result)