day14-正则表达式
一、什么是正则表达式
1、正则表达式:一种可以让复杂的字符串问题变得简单的工具
二、匹配类符号
1、fullmatch函数
- fullmatch( 正则表达式,字符串) - 判断字符串是否满足正则表达式描述的规则(如果不满足,结果就是None)
- 不管使用正则表达式解决什么样的字符串问题,写正则都是在描述字符串规则
# 导入函数
from re import fullmatch
2、所有匹配类符号
(1)普通符号 - 在正则表达式中本身的符号就是普通符号
result = fullmatch(r'abc','abc')
print(result) # <re.Match object; span=(0, 3), match='abc'>
(2). - 任意匹配一个字符
result = fullmatch(r'.bc','0bc')
print(result) # <re.Match object; span=(0, 3), match='0bc'>
(3)\d - 匹配任意一个数字字符
result = fullmatch(r'a\d\db','a86b')
print(result) # <re.Match object; span=(0, 4), match='a86b'>
(4)\s - 匹配任意一个空白字符
- 空白字符 - 所有能产生空白效果的字符:空格、\t、\n
result = fullmatch(r'a\sb','a\tb')
print(result) # <re.Match object; span=(0, 3), match='a\tb'>
(5)\w - 匹配任意一个数字、字母、下划线或者中文
result = fullmatch(r'a\wb','a你b')
print(result) # <re.Match object; span=(0, 3), match='a你b'>
(6)\D、\S、\W
- \后面跟大写字母对应的功能和\后面跟小写的功能相反
- \D - 匹配任意一个非数字字符
result = fullmatch(r'\Db\Sc\We','sbdc-e')
print(result)
(7)[字符集] - 匹配在字符集中任意一个字符
- [axd] - 匹配a、x、d中的任意一个
- [\dmn] - (\开头的特殊符号在中括号中还是有特殊意义)匹配任何一个数字或者m或者n
- [3-9mn] - (-在中括号中表示谁到谁)匹配3-9中的任意一个数字或者m或者n
- [a-z] - 匹配任意一个小写字母
- [A-Z] - 匹配任意一个大写字母
- [a-zA-Z] - 匹配任意一个字母
- [\u4e00 - \u9fa5] - 匹配任意一个文字
- 注意:中括号中的 - 只有放在两个字符之间才能表示谁到谁,如果放在中括号的最前面或者最后面,或者放在中括号外面减号只表示减号本身
result = fullmatch(r'a[xyzh]b','ahb')
result = fullmatch(r'[na\d]b','6b')
result = fullmatch(r'a[\u4e00-\u9fa5A-Z]b','a好b')
(8)[ ^字符集 ] - 匹配不在字符集中的任意一个字符
result = fullmatch(r'a[^A-Z]b','akb')
- 注意:[ ]里面的^ ,只有放在最前面才有特殊功能,如果不在最前面^就是普通符号
三、匹配次数相关符号
1、* - 0次或者多次(任意多次)
print(fullmatch(r'a*b', 'ab'))
print(fullmatch(r'.*b', 'ms23@b'))
print(fullmatch(r'[A-Z]*b', 'JDJEWb'))
2、+ - 1次或者多次
print(fullmatch(r'a+b', 'aaaaaab'))
3、? - 0次或者1次
print(fullmatch(r'a?b', 'b'))
4、{ }
- {N} - N次
- {M,N} - M到N次
- {M, } - 至少M次
- { ,N} - 最多N次
print(fullmatch(r'.a{3}b', 'aaaab'))
print(fullmatch(r'a{3,5}', 'aaaa'))
print(fullmatch(r'a{3,}b', 'aab'))
print(fullmatch(r'a{,3}b', 'aaaab'))
5、贪婪与非贪婪
- 匹配次数的不确定的时候匹配模式分为贪婪和非贪婪,默认是贪婪的
- 贪婪:在匹配成功的情况下,有多种匹配次数,贪婪取次数最多的那个次数(+、*、?、{M,N}、{M,}、{,N})
- 非贪婪:在匹配成功的情况下,有多种匹配次数,非贪婪取次数最少的那个次数(+?、*?、??、{M,N}?、{M,}?、{,N}?)
# 贪婪
print(match(r'a.+b', 'a1b奇数b社会b获得'))
# 非贪婪
print(match(r'a.+?b', 'a1b奇数b社会b获得'))
6、练习:写正则表达式可以匹配任意一个整数字符串(不考虑0)
# 匹配成功:'123'、'9'、'-234'、'+233'
# 匹配失败:'23m'、'--7283'、'++782'、'009'、'02'
print(fullmatch(r'[+-]?[1-9]\d*', '123'))
四、分组和分支
1、() - 分组
- 在正则表达式中可以用()将正则表达式中的部分内容括起来表示一个整体,一个()代表一个分组
(1)整体控制:以某个部分为单位对符号进行控制
print(fullmatch(r'([a-z]{2}\d{2})+', 'zx23hg67ih87xb23'))
(2)重复 - 在正则中通过\N来重复它前面第N个分组匹配到的结果
print(fullmatch(r'(\d{3})-\1', '456-456'))
print(fullmatch(r'([a-z]{2})(\d{3})=\2\1{2}', 'mn897=mn897mn'))
(3)捕获 - 获取匹配结果的某个部分
- 捕获分为自动捕获和手动捕获两种,只有findall具有自动捕获,其他情况需要手动捕获
- findall( 正则表达式,字符串) - 获取字符串中所有满足正则的子串
from re import findall
message = '年龄:18岁,身高:180,体重:120斤,月薪:5000元,房租:1000元'
result=findall(r'\d+',message)
print(result) # ['18', '180', '120', '5000', '1000']
# 自动捕获 - 自动获取匹配结果分组匹配到的内容
result=findall(r'(\d+)元',message)
print(result) # ['5000', '1000']
# 手动捕获 - 写额外的代码来获取匹配结果中分组匹配到的内容
result = fullmatch(r'(\d+)元','8292元')
print(result)
# 获取整个正则对应的匹配结果:匹配对象.group()
print(result.group()) # 8292元
2、| - 分支
- 正则1|正则2 - 先用正则1去匹配,如果匹配成功整个正则表达式就成功,如果匹配失败则用正则2匹配
# 匹配'23jhg'、'34卡萨丁'
# 方法1
print(fullmatch(r'\d{2}[a-z]{3}|\d{2}[\u4e00-\u9fa5]{3}', '23jhg'))
# 方法2
print(fullmatch(r'\d{2}([a-z]{3}|[\u4e00-\u9fa5]{3})', '34卡萨丁'))
五、检测类符号
- 检测类符号 - 在匹配成功的情况下,检测指定的位置是否符合相应的要求(不影响字符串的长度)
1、\b - 检测\b所在位置是否是单词边界
- 单词边界:英文符号中可以区分不同单词的符号(例如:空白符号、英文的标点符号、字符串开头、字符串结尾)
str1 = '123hdd632好好说说 879,822hdd212 你 898'
print(findall(r'\d+', str1)) # ['123', '632', '879', '822', '212', '898']
print(findall(r'\b\d+', str1)) # ['123', '879', '822', '898']
print(findall(r'\d+\b', str1)) # ['879', '212', '898']
print(findall(r'\b\d+\b', str1)) # ['879', '898']
2、^ - 检测是否是字符串开头
3、$ - 检测是否是字符串结尾
4、转义字符 - 在正则中有特殊意义的符号前加\,让整个符号变成普通符号
# '钱.567'
print(fullmatch(r'[\u4e00-\u9fa5]\.\d+', '钱.567'))
# '2*3'
print(fullmatch(r'\d\*\d', '2*3'))
5、re模块 - 模块全是和正则表达式相关的函数
# 导入模块
from re import fullmatch, match, search, findall, finditer, split, sub
- fullmatch(正则,字符串) - 匹配整个字符串(判断字符串是否符合正则描述的规则),匹配成功返回匹配对象,匹配失败返回None
- match(正则,字符串) - 匹配字符串开头(判断整个字符串开头是否符合正则描述的规则),匹配成功返回匹配对象,匹配失败返回None
- search(正则,字符串) - 匹配字符串中第一个满足正则的子串,匹配成功返回匹配对象,匹配失败返回None
- findall(正则,字符串) - 获取字符串中所有满足正则的子串,返回值是一个列表,列表中的元素是匹配到字符串
- finditer(正则,字符串) - 获取字符串中所有满足正则的子串,返回值是一个迭代器,迭代器中的元素是匹配对象
- split(正则,字符串) - 将字符串中所有满足正则的子串作为切割点对字符串进行切割
- sub(正则,字符串1,字符串2) - 将字符串2中所有满足正则的子串都替换成字符串1
str1 = '5453dhj 366解放军,获得hd765,87'
result = findall(r'\d+', str1)
print(result) # ['5453', '366', '765', '87']
result = finditer(r'\d+', str1)
print(result)
print(next(result)) # <re.Match object; span=(0, 4), match='5453'>
print(list(result))
result = split(r'\d+', str1)
print(result) # ['', 'dhj ', '解放军,获得hd', ',', '']
result = sub(r'\d+|[a-zA-Z]+', 'A', str1)
print(result) # AA A解放军,获得AA,A