python正则表达式
- 1.正则表达式的特点和优势
-
- 2.正则搜索方法
- 2.1 search() & match()
- 2.2 findall() & finditer()
- 2.3 fullmatch() & split()
- 2.4 正则表达式的转义
- 3.正则表达式规则
- 3.1 正则替换和编译
- 3.2 正则表达式
- 区间
- 符号
- 快捷标识
- ^ $
- 正则重复
- 贪婪模式和非贪婪模式
- 正则分组
- 分组向后引用
- 捕获分组和非捕获分组
- 命名分组
- 正则标记
- 零宽断言
- 内联标记
1.正则表达式的特点和优势
1.1 独立性
正则表达式运行的引擎是独立的,在几乎所有语言中都存在有正则表达式模块,正则表达式语法在各种语言上都是一样的,但是在实现方式上不尽相同。
1.2 优势
1.2.1 过滤查找
1.2.2 验证输入是否合法
2.正则搜索方法
2.1 search() & match()
2.1.1 search() 和 match() 查找
# 差异:
re.search()依据正则表达式进行匹配
re.match()只从字符串的开头匹配
# 相同点:
两者只会输出匹配找到的第一个符合要求的子字符串的match对象
查找到结果返回match对象,没有则返回None
# 实例
import re # 导入re模块
ret1 = re.search(r"sanle", "hello sanle") # 使用re.search()方法查找
print(ret1) # 返回一个match对象 或者 None 结果:
print(ret1.group()) # 通过match对象的group属性,访问其内容 结果:sanle
ret2 = re.match(r"hello", "hello sanle") # 使用re.search()方法查找
print(ret2) # 返回一个match对象 或者 None 结果:None
# result.start() result.end() 下标左闭右开区间 即[m,n)
print(ret2.start()) # 输出匹配字符串的开始下标
print(ret2.end()) # 输出匹配字符串的结束下标
print(ret2.group()) # 输出匹配到的字符串
# 结果:0 5 hello 即0->h ... 5->空格 hello为匹配到的字符串
2.2 findall() & finditer()
2.2.1 findall()和finditer()
# 规则:
# 相同点:
findall 或 finditer 匹配所有符合要求的字符串
# 不同点:
findall找到所有匹配内容,放到一个列表里返回
finditer找到所有内容,返回一个迭代器,惰性求值
finditer 遍历后得到的每个内容都是一个match对象,需要调用group来得到里面的具体的匹配字符串
findall 直接返回匹配的字符串列表
# Pattern.findall(string[,pos][,endpos]) 查询所有匹配,结果受到分组影响
# 如果没有分组,则返回与整个模式匹配的字符串列表。
# 如果恰好有一个组,请返回匹配该组的字符串列表。
# 如果存在多个组,则返回与组匹配的字符串的元组列表。
# 非捕获组不会影响结果的形式。使用了分组之后,findall不会输出分组以外的内容。
# 实例
import re
ret = re.findall("s.{6}","hello snale snachaung nihao world ssssssss")
print(ret) # findall 返回匹配字符串组成的列表
# 结果:
# ['snale s', 'sssssss']
result = re.findall("s.{6}","hello snale snachaung nihao world ssssssss")
for i in result:
print(i) # findall 返回列表 遍历元素
# 结果:
# sanle s
# sssssss
ret = re.finditer("s.{6}","hello snale snachaung nihao world ssssssss") # 返回一个迭代器
print(ret) # finditer 返回iterator,即迭代器
for i in ret:
print(i) # 从迭代器中得到了match对象 需要调用其group来遍历其匹配字符串内容
print(i.group()) # 从match对象中得到匹配的字符串
# 结果:
#
#
# sanle s
#
# sssssss
print(re.findall('[a-zA-Z]d{2,}','a1bc22342459f9849')) # ['c22342459', 'f9849']
print(re.findall('[a-zA-Z](d{2,})','a1bc22342459f9849')) # ['22342459', '9849']
# 使用分组功能,又要输出全部内容,那么就在整体外面再加一个括号
print(re.findall('([a-zA-Z](d{2,}))','a1bc22342459f9849')) # [('c22342459', '22342459'), ('f9849', '9849')]
2.3 fullmatch() & split()
# fullmatch(string[,pos[,endpos]]) 全部匹配
import re
print(re.search("张三","法外狂徒张三,来长沙了")) # 整个字符串进行匹配
print(re.match("张三","法外狂徒张三,来长沙了")) # 只匹配字符串开始 None
print(re.search("^张三","法外狂徒张三,来长沙了")) # 只匹配字符串开始 None
print(re.match("张三","法外狂徒张三,来长沙了"[4:])) #
print(re.fullmatch("张三","法外狂徒张三,来长沙了")) # 匹配字符串开始和结束位置 None
print(re.search("^张三$","法外狂徒张三,来长沙了")) # 匹配字符串开始和结束位置 None
print(re.fullmatch("张三","法外狂徒张三,来长沙了"[4:6])) #
# split(string,maxsplit=0) 根据匹配分割 受到分组的影响
print(re.split('[+-*/]','9+7-8*6/5')) # 结果:['9', '7', '8', '6', '5']
# 捕获分组 将匹配到的所有信息都匹配出来
print(re.split('([+-*/])','9+7-8*6/5')) # 结果:['9', '+', '7', '-', '8', '*', '6', '/', '5']
# maxsplit=0 指定分割的次数 默认是0不受限制
print(re.split('(?:[+-*/])','9+7-8*6/5',maxsplit=2)) # ['9', '7', '8*6/5']
print(re.split('([+-*/])','9+7-8*6/5',maxsplit=2)) # ['9', '+', '7', '-', '8*6/5']
2.4 正则表达式的转义
2.4.1 python中正则表达式转义工作流程
python正则表达式转义两次,分别是python自己转义一次和正则自己转义一次如:\t -->tab-->tab
即 python自己转义\为 t为tab键,之后交给正则来再一次转义即tab转义为tab 自动忽略单个的
正则表达式前+r表示抑制第一次的python转义,使python
直接将正则表达式传递给正则去转义,即只进行正则的转义,减少失误
r'tdv' -不转义字符,保持原始字符串 等价于 '\tdv' 即表示以raw string格式进行定义,可以防止字符串规避反斜杠的转义 直接将正则表达式传递给正则去转义
f'gajeo{name}' -定义格式字符串
b'12' -字符串bytes类型,以便服务器或浏览器识别bytes数据类型;
print(u'中国')
print(u'china')
-字符串前面加u表示以Unicode格式进行编码,往往用来解决中文乱码问题,一般英文字符串基本都可以正常解析,而中文字符串必须表明用什么编码,否则就会乱码。
# 实例
import re
result = re.search("snachaung \ttongle", "hello world,snachaung ttongle")
print(result)
# 结果:
result = re.search(r"snachaung \ttongle", "hello world,snachaung ttongle")
print(result)
# 结果:None
# 分析:前者没有+r即正则表达式进行了两次转义,先是\t->t,然后是t->tab;后者是只经历 \t->tab 然后丢弃单个的
3.正则表达式规则
3.1 正则替换和编译
3.1.1 正则替换
# 格式:
re.sub("匹配原则","替换内容",string)
匹配的所有元素都替换
# 实例
import re
str1 = "hello ,i'm learning python python"
print(re.sub("p.{2}","xixi",str1))
# hello ,i'm learning xixihon xixihon
3.1.2 正则编译
import re
msg = "hello my name is Jack Cali"
msg2 = "hello my name is Rose"
# 直接查找
result = re.findall("iss(.*)$", msg)
result2 = re.findall("iss(.*)$", msg2)
print(result, result2)
# 先编译再查找
reg = re.compile("iss(.*)$")
print(reg.findall(msg))
print(reg.findall(msg2))
# 区别
pass
3.2 正则表达式
区间
3.2.1 区间
# 区间: [] 根据ascii码确定区间范围 --要求ascii码小的在前,ascii码大的在后面如:[a-z]a->97,z->122
# 可以[A-z] A->65 z->122
# [] 区间表示 任选括号里一个字符进行匹配
# 实例
import re
ret = re.findall("[12pP]x", "2px 1xx Python pxoo") # 匹配中括号内任意一个字符开头,且以x结尾的两个长度的字符串
print(ret)
ret = re.findall("[0-9]", "124354raskgreg-grme23") # 匹配数字0-9任意字符
print(ret)
ret = re.findall("[A-Z]", "124354raskgreg-grme23") # 匹配大写字母A-Z
print(ret)
ret = re.findall("[a-z]", "124354raskgreg-grme23") # 匹配小写字母a-z
print(ret)
ret = re.findall("[A-Za-z0-9]", "124354raskgreg-grme23") # 匹配大小写字母和数字0-9
print(ret)
ret = re.findall("[a-z0-9A-Z-]", "124354raskgreg-grme23") # 匹配大小写字母和数字0-9及-
print(ret)
3.2.2 区间取反
ret = re.findall(r"[^A-z][0-9]","few2345rg43h6n5jdth") # 匹配不以A-z开头且匹配第二位是0-9数字的字符串
print(ret)
符号
3.2.3 匹配或
import re
msg = "四是四,十是十 十四是十四 四十是四十"
ret = re.search(r"四|十", msg)
print(ret.group())
ret2 = re.findall(r"四|十", msg)
print(ret2)
3.2.4 .占位符
# 表除(n以外)的任意字符
import re
ret = re.findall("p.thon","pXthon python p-thon pthon pnthon p thon")
print(ret)
3.2.5 ^ $
import re
ret = re.findall(r"^python","python1 is python")
print(ret)
ret = re.findall(r"python$","python1 is python")
print(ret)
ret = re.findall(r"^python$","python1 is python")
print(ret)
3.2.6 正则重复
# 通配符: * ? +
# ? 匹配前一项0次或1次
# + 匹配前一项1次以上 1-n次
# * 匹配前一项任意次 0-n次
# {n,m} 匹配前一项n-m次 {n,} {,m} {n}
# 实例
import re
ret = re.findall('py?', "pythonppyy")
print(ret) # 结果:['py', 'p', 'py']
ret = re.findall('py+', "pythonppyy")
print(ret) # 结果:['py', 'pyy']
ret = re.findall('py*', "pythonppyy")
print(ret) # 结果:['py', 'p', 'pyy']
ret = re.findall('py{1,3}', "pythonppyy")
print(ret) # 结果:['py', 'pyy']
ret = re.findall('py{1,}', "pythonppyyyy") # 匹配前一项1次到多次
print(ret) # 结果:['py', 'pyyyy']
ret = re.findall('py+', "pythonppyyyy") # 匹配前一项1次到多次
print(ret) # 结果:['py', 'pyyyy']
ret = re.findall('py{,3}', "pythonppyyyy") # 匹配前一项3次以下
print(ret) # 结果:['py', 'p', 'pyyy']
ret = re.findall('py{3}', "pythonppyyyy") # 匹配前一项3次
print(ret) # 结果:['pyyy']
快捷标识
3.2.7 快捷标识
A 匹配字符串开始
b 匹配词边界
B 匹配非词边界
w 匹配单词字符 a A 123 中文
W 匹配非单词字符
d 匹配数字
D 匹配非数字
s 匹配空白
S 匹配非空白
# 实例
# 匹配字符串的开始
import re
ret = re.findall(r"Ahello", "hello world hello")
print(ret)
# 词边界
ret = re.findall(r"bwordB", "word123 word# abcword #word你好")
print(ret)
# 匹配单词字符
ret1 = re.findall(r"wwordW", "word123 word# abcword #word你好")
print(ret1)
ret2 = re.findall(r"wwordW", "中国word*56w A1word# abcword #word你好")
print(ret2)
# 匹配数字和非数字
ret = re.findall(r"dwordD", "word123 1word# abcword #word你好")
print(ret)
# 匹配空白和非空白
ret = re.findall(r"swordS", "word123 word# abcword #word你好")
print(ret)
^ $
import re
ret = re.findall(r"^python","python1 is python") # 匹配字符串以python开头的python字符串
print(ret) # 结果:['python']
ret = re.findall(r"python$","python1 is python") # 匹配字符串以python结尾的python字符串
print(ret) # 结果:['python']
ret = re.findall(r"^python$","python1 is python") # 匹配以python字符串开头和结尾的python字符串
print(ret) # 结果:[]
正则重复
# 通配符: * ? +
# ? 匹配前一项0次或1次
# + 匹配前一项1次以上 1-n次
# * 匹配前一项任意次 0-n次
# {n,m} 匹配前一项n-m次 {n,} {,m} {n}
import re
ret = re.findall('py?', "pythonppyy")
print(ret) # 结果:['py', 'p', 'py']
ret = re.findall('py+', "pythonppyy")
print(ret) # 结果:['py', 'pyy']
ret = re.findall('py*', "pythonppyy")
print(ret) # 结果:['py', 'p', 'pyy']
ret = re.findall('py{1,3}', "pythonppyy")
print(ret) # 结果:['py', 'pyy']
ret = re.findall('py{1,}', "pythonppyyyy") # 匹配前一项1次到多次
print(ret) # 结果:['py', 'pyyyy']
ret = re.findall('py+', "pythonppyyyy") # 匹配前一项1次到多次
print(ret) # 结果:['py', 'pyyyy']
ret = re.findall('py{,3}', "pythonppyyyy") # 匹配前一项3次以下
print(ret) # 结果:['py', 'p', 'pyyy']
ret = re.findall('py{3}', "pythonppyyyy") # 匹配前一项3次
print(ret) # 结果:['pyyy']
贪婪模式和非贪婪模式
# 贪婪模式 尽可能地匹配长的字符串
# 非贪婪模式 从左至右依次匹配 匹配到就结束本字段匹配 然后进行后面的字符串匹配 (+? *? {2,4}?)
# 默认为贪婪模式
import re
ret = re.findall("py*","pythonpyyyyy")
print(ret) # 结果:['py', 'pyyyyy']
# 非贪婪模式
import re
msg = "cats and dogs,cats1 and dogs1"
print(re.findall(r"c.*?s",msg)) # 结果:['cats', 'cats']
import re
ret = re.findall("py*?","pythonpyyyyy")
print(ret) # 结果:['p', 'p']
正则分组
# group 默认参数是0 表示输出整个匹配字符串
# 参数 n (n>0)输出第几个组的匹配字符串
msg = "tel:173-7572-2991"
ret = re.search(r"(d{3})-(d{4})-(d{4})",msg)
print(ret.group()) # 输出匹配到的字符串
print(ret.group(0)) # 输出匹配到的字符串
print(ret.group(1)) # 输出匹配到的第一组的子字符串
print(ret.group(2)) # 输出匹配到的第二组的子字符串
print(ret.group(3)) # 输出匹配到的第三组的子字符串
分组向后引用
# 前面的匹配内容会保存在内存里面,后面匹配从内存里查找
msg = "tel:173-7572-2991"
msg = "tel:173-7572-173"
ret = re.search(r"(d{3})-(d{4})-1", msg) # 1表示匹配第一组子字符串
print(ret.group()) # 只有match对象才有group属性 AttributeError: 'NoneType' object has no attribute 'group'
# 结果:173-7572-173
捕获分组和非捕获分组
# 捕获分组
# 分组之后匹配到的数据会发放在内存里,并且给定一个从1开始的索引
# 捕获分组是可以进行分组向后引用
# 非捕获分组(?:正则表达式)
# 只分组不捕获 匹配到的分组数据不放在内存里
# 不能使用分组向后引用
import re
msg = "tel:173-7572-7572"
ret = re.search(r'(?:d{3})-(d{4})-1', msg)
print(ret.group(0)) # 打印匹配字符串 结果:173-7572-7572
print(ret.group(1)) # 打印第一个捕获分组 结果:7572
# 如果有捕获分组 findall只会匹配捕获分组里的内容
import re
msg = "tel:173-7572-7572"
ret = re.findall(r'(?:d{3})-(d{4})-1', msg)
print(ret) #结果:['7572']
命名分组
# 命名分组 (?P<名字>正则表达式)
import re
msg = "tel:173-7572-7572"
ret = re.search(r'(?Pd{3})-(d{4})-2', msg)
print(ret.group())
print(ret.group("first"))
print(ret.groupdict())
# 结果:173-7572-7572
173
{'first': '173'}
正则标记
# 正则标记 --改变正则表达式的默认匹配规则 如大小写是否敏感
msg = """YOU JUMP, I GO
you jump, i go"""
# 对大小写不敏感的标记
ret = re.findall(r"JUMP", msg, re.I) # 忽略大小写
print(ret) # 结果:['JUMP', 'jump']
# 多行模式
ret = re.findall(r"^YOU JUMP, I GO$", msg, re.I | re.M) # 忽略大小写 且运用多行模式
print(ret) # 结果:['YOU JUMP, I GO', 'you jump, i go']
# re.S 让.匹配任意字符 包括换行符
ret = re.findall(r"^you.*go$", msg, re.I | re.S) # 忽略大小写 且让.匹配任意字符包括换行符
print(ret) # 结果:['YOU JUMP, I GO nyou jump, i go']
零宽断言
# 零宽断言
# 不占用匹配宽度,只用来确定位置
# 与驴不占用匹配宽度,只用来确定位置
str1 = "红鲤鱼与绿鲤鱼与驴"
print(re.findall(r".鲤鱼(?=与驴)", str1)) # 匹配后面有与驴的鲤鱼
print(re.findall(r".鲤鱼(?!与驴)", str1)) # 匹配后面没有与驴的鲤鱼
print(re.findall(r"(?<=红)鲤鱼.", str1)) # 匹配前面有红的鲤鱼
print(re.findall(r"(?
内联标记
# 修饰符 功能
# (?imx)re 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
# (?imx:re) 在括号中使用i, m, 或 x 可选标志
# 内联标记 只想在某个地方使用忽略 而不在其他地方忽略?可以使用内联标记
# 内联标记实际就是匹配模式的部分范围生效
# re.IGNORECASE 与 (?i:) 括号内忽略大小写
# re.MULTILINE 与 (?m:) '^'和'$'的跨行限制开头结尾 括号内实现多行模式
# re.DOTALL 与 (?s:) 让 '.'支持换行符的匹配。 括号内实现.代表所有字符包括换行/n
# re.VERBOSE 与 (?x:) 支持注释 括号内实现注释
# re.ASCII 与 (?a:) 让 w, W, b, B, d, D, s 和 S 只匹配ASCII 括号内只匹配ascii
# (?i:正则表达式) 括号内大小写不敏感
a = re.compile("(super) APP")
x = a.search("SUPER APP")
print(x) #不能用super匹配SUPER
a = re.compile("(?i:super) APP") # 忽略大小写进行匹配
x = a.search("SUPER APP")
print(x) # #可以用super匹配SUPER 。
# (?i)re
import re
ret = re.findall('(?i)^python$','PYTHON') # 忽略大小写
print(ret) # 结果:['Python']
ret = re.findall('(?i)^python$','Pythonnpython')
print(ret) # 结果:[]
ret = re.findall('(?im)^python$','Pythonnpython') #多行模式
print(ret) # 结果:['Python', 'python']
# (?imx:re)
import re
msg = "Hello Python"
ret = re.findall('(?i:hello) python',msg)
print(ret) # 结果:[]
ret = re.findall('(?i:hello) Python',msg)
print(ret) # 结果:['Hello Python']
# (?is:re) 大小写不敏感 且.代表左右的字符串包含换行n
a = re.compile(r'(?i:天天.*up)')
str_ = '天天UP天天nUP'
x = re.match(a,str_)
print(x) # #点号不能匹配换行符
a = re.compile(r'(?is:天天.*up)')
str_ = '天天UP天天nUP'
x = re.match(a,str_)
print(x) # #支持忽略大小写,并让点号匹配换行符
# 排除标记方式
# 比如flasg属性中 已经制定了忽略大小写 但是在某些地方一定会
# 不能忽略大小写 那么就可以设置排除标记方式
# 格式:(?-im:re) im为要忽略的属性 可以是其他任何存在的属性
a = re.compile(r'(?-i:None).*empty',re.IGNORECASE)
str_1 = 'none expressing EMPTY'
str_2 = 'None expressing EMPTY'
x = a.match(str_1)
print(x) # 结果:None 因为str_1中none大小写敏感 所以无匹配项
y = a.match(str_2) # 分组内大小写敏感 分组外大小写不敏感
print(y) # 结果: