1 认识正则表达式
-
什么是正则表达式
正则表达式是一种可以让一些复杂字符串问题变得简单的工具。
正则并不是Python特有的语法(不属于python),所有高阶语言都支持正则,正则语法通用。
不管通过正则表达式解决的是什么问题,写正则的时候都是在使用正则表达式描述字符串规则。
🍿判断指定的字符串是否是一个合法的手机号。
11位,每一位都是数字,首位是1,第二位是3~9
tel = input('请输入手机号:') # 方法一 def is_tel(num: str): if len(num) != 11: return False for i in num: if not i.isdigit(): return False if num[0] != '1': return False if '3' <= num[1] <= '9': return True return False print(is_tel(tel)) # 方法二 def is_tel2(num: str): from re import fullmatch return bool(fullmatch(r'1[3-9]\d{9}', num)) print(is_tel2(tel))
🍿提取字符串中所有的数字子串。
str1 = '月薪: 25360元, 年龄18岁。身高:175,体重120斤。23' # ['25360', '18', '175', '120'] # 方法一: result = [] temp = '' for x in str1: if x.isdigit(): temp += x else: if temp: result.append(temp) temp = '' if temp: result.append(temp) print(result) # 方法二: from re import findall result = findall(r'\d+', str1) print(result)
-
Python的re模块
re模块是Python用来支持正则表达式的一个模块,模块中包含了所有和正则相关的函数。
fullmatch(正则表达式,字符串) 判断正则表达式和指定的字符串是否完全匹配(判断整个字符串是否符合正则表达式所描述的规则)
如果匹配成功返回匹配对象,匹配失败返回None。
导入模块
from re import fullmatch
-
正则语法
-
匹配类符号
符号 说明 普通符号 在正则表达式中表示符号本身的符号 . 匹配任意一个字符 \d 匹配任意一个数字字符 \s 匹配任意一个空白字符 \D 匹配任意一个非数字字符 \S 匹配任意一个非空白字符 [字符集] 匹配字符集中的任意一个字符 [ ^ 字符集] 匹配不在字符集中的任意一个字符
1)普通符号
from re import fullmatch result = fullmatch(r'abc', 'abc') print(result) #<re.Match object; span=(0, 3), match='abc'>
2).
result = fullmatch(r'a.c', 'a.c') print(result) #<re.Match object; span=(0, 3), match='a.c'> result = fullmatch(r'a.c', 'a+c') print(result) #<re.Match object; span=(0, 3), match='a+c'> result = fullmatch(r'a..c', 'a*&c') print(result) #<re.Match object; span=(0, 4), match='a*&c'>
3)\d
result = fullmatch(r'a\dc', 'a0c') print(result) #<re.Match object; span=(0, 3), match='a0c'>
4)\s
空白字符:能产生空白效果的字符,例如:空格、换行、水平制表符。
result = fullmatch(r'a\sc', 'a c') print(result) #<re.Match object; span=(0, 3), match='a c'>
5)\D
result = fullmatch(r'a\Dc', 'a c') print(result) #<re.Match object; span=(0, 3), match='a c'> result = fullmatch(r'a\Dc', 'a2c') print(result) #None
6)\S
result = fullmatch(r'a\Sc', 'a2c') print(result) #<re.Match object; span=(0, 3), match='a2c'> result = fullmatch(r'a\Sc', 'a\tc') print(result) #None
7)[字符集]
result = fullmatch(r'zhou[and]shen', 'zhouashen') print(result) #<re.Match object; span=(0, 9), match='zhouashen'> result = fullmatch(r'[\u4e00-\u9fa5]', '哈') print(result) #<re.Match object; span=(0, 1), match='哈'>
[]中减号放在两个字符之间表示谁到谁(确定的方式是根据字符编码值大小确定的);如果减号不在两个字符之间,就表示一个普通的减号。
🌰栗子:
[abc]:匹配a或者b或者c
[abc\d]、[c\dba]:匹配a或者b或者c或者任意一个数字
[2-8]:匹配2到8中任意一个数字(前者的编码值小于后者)
[a-z]:匹配任意一个小写字母
[a-zA-Z]、[A-Za-z]:匹配任意一个字母
[a-zA-Z\d_]:匹配字母数字下划线
[\u4e00-\u9fa5]:匹配任意一个中文字符
8)[ ^ 字符集]
^在最前面。
result = fullmatch(r'[^\u4e00-\u9fa5]', '哈') print(result) #None
-
匹配次数
符号 说明 * 0次或多次(任意次数) + 1次或者多次(至少一次) ? 0次或1次 {M,N} M到N次 {M,} 至少M次 {,N} 最多N次 {N} N次 1)*
注意:*在谁的后面控制的就是谁的次数。
匹配符号*
result = fullmatch(r'a*11', 'aaa11') print(result) #<re.Match object; span=(0, 5), match='aaa11'> result = fullmatch(r'[ab]*11', 'abbaa11') print(result) #<re.Match object; span=(0, 7), match='abbaa11'>
2)+
result = fullmatch(r'[ab]+11', '11') print(result) #None result = fullmatch(r'[ab]+11', 'b11') print(result) #<re.Match object; span=(0, 3), match='b11'>
3)?
result = fullmatch(r'a?11', 'aa11') print(result) #None
4){}
result = fullmatch(r'zs{3}', 'zsss') print(result) #<re.Match object; span=(0, 4), match='zsss'> result = fullmatch(r'zs{1,2}', 'zs') print(result) #<re.Match object; span=(0, 2), match='zs'> result = fullmatch(r'zs{3,}', 'zssss') print(result) #<re.Match object; span=(0, 5), match='zssss'> result = fullmatch(r'zs{2,}', 'zss') print(result) #<re.Match object; span=(0, 3), match='zss'>
🧈练习1:写一个正则,判断输入的内容是否是一个合法的QQ号(长度是5~12位的数字,第一位不能是0)
qq = '123204832' result = fullmatch(r'[1-9]\d{4,11}', qq) if result: print('合法') else: print('不合法')
🧈练习2:判断输入的内容是否是一个合法的标识符(由字母、数字下划线组成,数字不能开头)
str1 = '_csdw2dhj' result = fullmatch(r'[a-zA-Z_][a-zA-Z_\d]*', str1) if result: print('合法') else: print('不合法')
2 贪婪和非贪婪
当匹配次数不确定的时候(*、+、?、{M,N}、{M,}、{,N}),匹配模式分为贪婪和非贪婪,默认是贪婪的。
-
贪婪:在匹配成功的时候,有多种匹配结果,贪婪取最多次数对应的匹配结果(匹配次数不确定的地方,有多种匹配方式都可以匹配成功,贪婪取最多次数)。
贪婪模式:*、+、?、{M,N}、{M,}、{,N}
-
非贪婪:在匹配成功的时候,有多种匹配结果,非贪婪取最少次数对应的匹配结果(匹配次数不确定的地方,有多种匹配方式都可以匹配成功,非贪婪取最少次数)。
非贪婪模式:*?、+?、??、{M,N}?、{M,}?、{,N}?
match(正则表达式,字符串) 判断字符串开头是否符合正则表达式描述的规则
from re import match # 贪婪模式 result = match(r'a.+b', 'amb计算bxxbmn') print(result) # <re.Match object; span=(0, 9), match='amb计算bxxb'> # 非贪婪模式 result = match(r'a.+?b', 'amb计算bxxbmn') print(result) # <re.Match object; span=(0, 3), match='amb'> # 注意:如果匹配结果只有一种可能,那么贪婪和非贪婪的结果一样 result = match(r'a.+b', 'ambxx') print(result) # <re.Match object; span=(0, 3), match='amb'> result = match(r'a.+?b', 'ambxx') print(result) # <re.Match object; span=(0, 3), match='amb'>
注意:如果匹配结果只有一种可能,那么贪婪和非贪婪的结果一样。
3 分组和分支
-
分组()
1)整体:将正则表达式中的一部分作为一个整体进行相关操作。
result=fullmatch(r'(\d\d[A-Z]{2})+','23HJ') print(result) #<re.Match object; span=(0, 4), match='23HJ'>
2)重复:可以在正则表达式中通过\M来重复它前面的第M个分组的匹配结果。
result = fullmatch(r'(\d{2})[A-Z]\1', '23H03') print(result) #None result = fullmatch(r'(\d{2})[A-Z]\1', '23H23') print(result) #<re.Match object; span=(0, 5), match='23H23'> result = fullmatch(r'(\d{2})([A-Z]{2})=\2\1', '23ED=ED23') print(result) #<re.Match object; span=(0, 9), match='23ED=ED23'>
注意:\M只能重复在它之前出现的内容,不能重复在它之后出现的内容。
3)捕获:只获取正则表达式中的一部分匹配到的结果(分为手动捕获和自动捕获。)
🧈提取message中金额对应的数字子串。
from re import findall message = '我今年18岁,月薪500000元,交300元腾讯会员费,放贷2000元。' result = findall(r'(\d+)元', message) print(result) #['500000', '300', '2000']
-
分支|
正则1|正则2|正则3|... 匹配可以和多个正则中任意一个正则匹配的字符串。
🧈匹配一个字符串是三个数字或者两个小写字母。
result = fullmatch(r'\d{3}|[a-z]{2}', '323') print(result) #<re.Match object; span=(0, 3), match='323'> result = fullmatch(r'a(\d{3}|[a-z]{2})b', 'a323b') print(result) #<re.Match object; span=(0, 5), match='a323b'>
如果想要正则表达式中的一部分实现多选一的效果,变化到的部分用分组表示。
4 转义符号
-
转义符号
正则中的转义符号,就是本身具备特殊功能或者特殊意义的符号前加’',让这个符号变成一个普通符号。
result = fullmatch(r'\d\+\d=\d', '1+2=3') print(result) #<re.Match object; span=(0, 5), match='1+2=3'> result = fullmatch(r'\\d\+\\d=d{2}', '\d+\d=dd') print(result) #<re.Match object; span=(0, 8), match='\\d+\\d=dd'>
-
[]里面的转义符号
单独存在有特殊意义的符号(+、*、?、.等),在[]中特殊意义会自动消失。
result = fullmatch(r'\d[+]\d=\d', '1+2=3') print(result) #<re.Match object; span=(0, 5), match='1+2=3'>
本身在中括号中有特殊功能的符号,如果要表示普通符号必须加’'。
result = fullmatch(r'a[MN-]b', 'a-b') result = fullmatch(r'a[M\-N]b', 'a-b') result = fullmatch(r'a[M^N]b', 'a^b') result = fullmatch(r'a[\^MN]b', 'a^b')
5 检测类符号
检测类符号是在匹配成功的情况下,检测检测类符号所在的位置是否符合相关要求。
符号 | 说明 |
---|---|
\b | 检测是否是单词边界 |
\B | 检测是否不是单词边界 |
^ | 检测是否是字符串开头 |
$ | 检测是否是字符串结尾 |
单词边界:可以将两个单词分开或者区分开的符号都是单词边界。比如:空白符号、英文标点符号、字符串开头和字符串结尾。
result = fullmatch(r'abc\b mn', 'abc mn')
print(result) #<re.Match object; span=(0, 6), match='abc mn'>
result = findall(r'\b\d+', message)
print(result) #['929', '999']
result = findall(r'\B\d+', message)
print(result) #['29', '1314', '929', '99']
result = findall(r'^\d+', message)
print(result) #['929']
result = findall(r'^.{5}', message)
print(result) #['929zs']
result = findall(r'.{5}$', message)
print(result) #['球,999']
6 re模块常用函数
-
常用函数
表达式 说明 fullmatch(正则表达式,字符串) 完全匹配,判断整个字符串是否符合正则表达式描述的规则,匹配成功返回匹配对象,匹配失败返回空 match(正则表达式,字符串) 匹配字符串开头,判断字符串开头是否符合正则表达式描述的规则,匹配成功返回匹配对象,匹配失败返回空 search(正则表达式,字符串) 获取字符串中第一个能够和正则匹配成功的子串,能找到返回匹配对象,找不到返回空 findall(正则表达式,字符串) 获取字符串中所有满足正则的子串,返回一个列表,列表中的元素是字符串;注意:如果正则表达式中有分组,会针对分组做自动捕获(只获取分组匹配的结果) finditer(正则表达式,字符串) 获取字符串中所有满足正则的子串,返回一个迭代器,迭代器中的元素是每个子串对应的匹配对象 split(正则表达式,字符串) 将字符串中所有满足正则的子串作为切割点对字符串进行切割 sub(正则表达式,字符串1,字符串2) 将字符串中所有满足正则的子串都替换成字符串1 导入模块:
from re import *
result = fullmatch(r'\d{3}', '234') print(result) result = match(r'\d{3}', '823介绍数据库') print(result) result = search(r'\d{3}', 'ba203还是678说') print(result) result = findall(r'\d{3}', 'ba203还是678说kk0222jksn就是23311') print(result) result = finditer(r'\d{3}', 'ba203还是678说kk0222jksn就是23311') print(result) # print(next(result)) print(list(result)) str1 = '123aMKnb嗑生嗑死aKKssa923b===' # 将str1中的a和b作为切割点对字符串进行切割 result = split(r'a|b', str1) print(result) # ['123', 'MKn', '嗑生嗑死', 'KKss', '923', '==='] result = sub(r'\d+', '+', 'ba203还是678说kk0222jksn就是23311') print(result)
-
匹配对象
1)直接获取整个正则表达式对应的匹配结果:匹配对象.group()
2)手动捕获某个分组对应的匹配结果:匹配对象.group(分组数)
3)获取匹配结果在原字符串中的位置:匹配对象.span()
result = search(r'(\d{3})([A-Z]{2})', '-=2设计师234KM2239KH') print(result) # <re.Match object; span=(6, 11), match='234KM'> print(result.group()) # '234KM' print(result.group(1)) # '234' print(result.group(2)) # 'KM' print(result.span()) # (6, 11) print(result.span(2)) #(9, 11)
-
参数
1)匹配忽略大小写(?i)写在正则表达式最前面
result = fullmatch(r'(?i)abc', 'AbC') print(result) #<re.Match object; span=(0, 3), match='AbC'>
2)单行匹配(?s):匹配的时候.能和换行进行匹配
多行匹配(默认):匹配的时候.不能和换行进行匹配
result = fullmatch(r'abc.123', 'abc\n123') print(result) # None result = fullmatch(r'(?s)abc.123', 'abc\n123') print(result) # <re.Match object; span=(0, 7), match='abc\n123'>