一.正则表达式
1.匹配单个字符
import re
lst = re.findall(正则表达式,要匹配的字符串)
返回列表,按照正则表达式匹配到的内容都扔到列表里
最好在正则表达式和要匹配的字符串前面都加上r,原型化输出字符串
1.预定义字符集
-
d匹配数字
-
D匹配非数字
-
w匹配字母或数字或下划线(正则函数中,支持中文的匹配)
-
W匹配非字母或数字或下划线
-
s匹配任意的空白符( )
-
S匹配任意非空白符
-
匹配一个换行符
-
匹配一个制表符
-
.匹配任意字符,除了换行符
2.字符组 必须匹配中括号里列举的字符(默认必须选一个)
lst = re.findall("[abc]","oputuopctyauobpt")
print(lst)
print(re.findall('a[abc]b','aab abb acb adb')) # aab abb acb
print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb'))#a1b a2b a3b
# 优化: -是一个特殊的字符,代表的是一个范围 0-9 0123456789
print(re.findall('a[0-9]b','a1b a2b a3b acb ayb'))#a1b a2b a3b
print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) #acb adb
# 优化: [a-g] 如果想要表达所有的26个小写字母[a-z]
print(re.findall('a[a-g]b','a1b a2b a3b acb ayb adb')) #acb adb
print(re.findall('a[ABCDEFG]b','a1b a2b a3b aAb aDb aYb')) #aAb aDb
# 优化: [A-G] 如果想要表达所有的26个大写字母[A-Z]
print(re.findall('a[A-G]b','a1b a2b a3b aAb aDb aYb')) #aAb aDb
print(re.findall('a[0-9a-zA-Z]b','a-b aab aAb aWb aqba1b')) #aab aAb aWb aqb a1b
# 注意: [0-z] 数字 小写 大写 还有特殊字符 比如@ ...
print(re.findall('a[0-z]b','a@b aab aAb aWb aqba1b')) # a@b aab aAb aWb aqb a1b
print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) # a1/b
^ 在字符组当中,代表除了,放到字符组的左边第一个位置
如果想要匹配^或者 - 或者,可在原来的字符前面加上,让字符的含义失效
print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) # a%b a&b
lst = re.findall(r"e[^-]f","e^f e-f")
lst = re.findall(r"a\c","ac")
print(lst) #a\c
print(lst[0])#ac
-> 转义字符 代表退格键backspace
2.匹配多个字符
1.量词练习
- ?匹配0个或者一个
print(re.findall('a?b','abbzab abb aab')) # ab b ab ab b ab
- +匹配一个或者多个
print(re.findall('a+b','b ab aaaaaab abb')) # ab aaaaaab ab
- *匹配0个或者多个
print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b
- {m,n}匹配m个至n个
# (1) 1 <= x <= 3
print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # aaab ab aab ab aab
# (2) 前面修饰的a , 必须是2个字符
print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab
# (3) 前面修饰的a , 至少是2个字符
print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab
2.贪婪模式与非贪婪模式
贪婪模式:默认向更多次匹配,底层用的是回溯算法
非贪婪模式:默认向更少次匹配,用一个?号来进行修饰(修饰在量词的身后)
(1)量词( * ? + {} )加上问号?表示非贪婪 惰性匹配
(2)例:.*?w 表示匹配任意长度任意字符遇到一个w就立即停止
回溯算法:从左向右进行匹配,一直到最后,直到最后再也匹配不到了,回头寻找最后一个
. 是匹配任意字符,除了换行符
strvar = "刘能和刘老根和刘铁棍子777子888"
lst = re.findall("刘.",strvar)
print(lst) # ['刘能', '刘老', '刘铁']
# 贪婪模式
lst = re.findall("刘.?",strvar)
print(lst) # ['刘能', '刘老', '刘铁']
lst = re.findall("刘.+",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子888']
lst = re.findall("刘.*",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子888']
lst = re.findall("刘.{1,21}",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子888']
lst = re.findall("刘.*子",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子']
# 非贪婪模式
lst = re.findall("刘.??",strvar)
print(lst) # ['刘', '刘', '刘']
lst = re.findall("刘.+?",strvar)
print(lst) # ['刘能', '刘老', '刘铁']
lst = re.findall("刘.*?",strvar)
print(lst) # ['刘', '刘', '刘']
lst = re.findall("刘.{1,21}?",strvar)
print(lst) # ['刘能', '刘老', '刘铁']
lst = re.findall("刘.*?子",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子']
3.边界符 ^ $
1) 本身是一个转义字符 backspace
边界字符 卡单词 word
卡住左边界 w
卡住有边界 d
strvar = "word pwd scf"
lst = re.findall(r".*d",strvar)
print(lst) # ['word pwd']
lst = re.findall(r".*?d",strvar)
print(lst) # ['word', ' pwd']
lst = re.findall(r"w",strvar)
print(lst) # ['w']
lst = re.findall(r"w.*?",strvar)
print(lst) # ['w']
# 正则表达式中写字符时,要谨慎,下面例子必须匹配到第一个空格时,才结束
lst = re.findall(r"w.*? ",strvar)
print(lst) # ['word ']
lst = re.findall(r"wS*",strvar)
print(lst) # ['word']^ $
- ^ $
^ 必须以..开头
$ 必须以..结尾
如果出现了^ $,要把字符串看成一个整体
strvar = "大哥大嫂大爷"
print(re.findall('大.',strvar)) # ['大哥', '大嫂', '大爷']
print(re.findall('^大.',strvar)) # ['大哥']
print(re.findall('大.$',strvar)) # ['大爷']
print(re.findall('^大.$',strvar))# []
print(re.findall('^大.*?$',strvar)) # ['大哥大嫂大爷']
print(re.findall('^大.*?大$',strvar)) # []
print(re.findall('^大.*?爷$',strvar)) # ['大哥大嫂大爷']
print(re.findall('^g.*? ' , 'giveme 1gfive gay')) # ['giveme ']
print(re.findall('five$' , 'aassfive')) # five
print(re.findall('^giveme$' , 'giveme')) # giveme
print(re.findall('^giveme$' , 'giveme giveme'))# []
print(re.findall('giveme' , 'giveme giveme')) # ['giveme', 'giveme']
print(re.findall("^g.*e",'giveme 1gfive gay')) # ['giveme 1gfive']
print(re.findall('g.*?', 'giveme 1gfive gay')) #['g', 'g', 'g']
print(re.findall("^g.*?e",'giveme 1gfive gay'))#['give']
4.命名分组
1)分组练习(用圆括号),要所有的姓名
print(re.findall('.*?_good','wusir_good alex_good secret男_good'))
# ['wusir_good', ' alex_good', ' secret男_good']
# () 显示括号里面匹配到的内容
print(re.findall('(.*?)_good','wusir_good alex_good secret男_good'))
# ['wusir', ' alex', ' secret男']
# ?: 不优先显示括号里面的内容
print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))
# ['wusir_good', ' alex_good', ' secret男_good']
- | 代表或 , a|b 匹配字符a 或者 匹配字符b
# 基本语法
strvar = "abcddd"
lst = re.findall("a|b",strvar) #['a', 'b']
print(lst)
# 注意事项
# 匹配abc 或者 abcd
"""
为了避免优先匹配前面的字符串,导致字符串匹配不完整,
把较难匹配到的字符串写在前面,容易匹配到的字符串放在后面
"""
strvar = "abc24234234ddabcd234234"
# lst = re.findall("abc|abcd",strvar) 注意
# print(lst) # ['abc', 'abc']
lst = re.findall("abcd|abc",strvar)
print(lst) # ["abc","abcd"]
3)练习
. 除了
,能够匹配到任意字符
功效: 让有意义的字符变得无意义,或者让无意义的字符变得有意义
. 让点原来的特殊含义失效,只是单纯的表达一个点字符.
# (1)匹配小数
strvar = "5.33 3.13 34 34. .98 9.99 sdfsdf ......"
# 整数.小数
lst = re.findall(r"d+.d+",strvar)
print(lst) #['5.33', '3.13', '9.99']
# (2)匹配小数和整数
# 整数.小数 34 43234 .
# d+
# d+.d+
lst = re.findall(r"d+.d+|d+",strvar)
print(lst) # ['5.33', '3.13', '34', '34', '98', '9.99']
用分组形式来做
findall 这个函数优先显示括号里面的内容,
如果不想显示括号内容,使用?:, 显示实际匹配到的内容
lst = re.findall(r"d+(?:.d+)?",strvar)
print(lst) # ['5.33', '3.13', '34', '34', '98', '9.99']
# 匹配135或171的手机号
strvar = "asdfasd234 13591199444 17188886666 19145547744"
lst = re.findall("(?:135|171)d{8}",strvar)
print(lst)
# 卡主开头和结尾,数字必须是11位
strvar = "13591199444"
lst = re.findall("^(?:135|171)[0-9]{8}$",strvar)
print(lst)
4)search函数
findall 把所有匹配到的字符串都搜出来,返回列表
不能把分组内容和匹配的内容同时显示出来
search 只要搜索到一个结果就返回,返回对象.
可以把分组内容和匹配的内容同时显示出来
group : 对象.group() 直接获取匹配到的内容
groups: 对象.groups() 直接获取分组里面的内容
# 匹配www.baidu.com 或者 www.oldboy.com
strvar = "www.baidu.com"
lst = re.findall("(?:www).(?:baidu|oldboy).(?:com)",strvar)
print(lst)
obj = re.search("(www).(baidu|oldboy).(com)",strvar)
print(obj)
# 获取的是匹配到的数据
print(obj.group()) #www.baidu.com
# 获取的是分组里面的数据
print(obj.groups()) #('www', 'baidu', 'com')
# 获取第一个小括号里面的内容
print(obj.group(1))
# 获取第二个小括号里面的内容
print(obj.group(2))
# 获取第三个小括号里面的内容
print(obj.group(3))
案例
# ### 案例: "5*6-7/3" 匹配 5*6 或者 7/3
"""search 在匹配不到时,返回的是None,无法使用group"""
# 匹配出5*6
strvar = "5*6-7/3"
# 匹配出5*6
obj = re.search(r"d+[*/]d+",strvar)
print(obj)
strvar1 = obj.group()
print(strvar1) # 5*6
# 按照*号分隔,算出乘积结果
n1,n2 = strvar1.split("*")
res1 = int(n1)*int(n2)
print(res1)
# 对字符串进行替换
# strvar = "30-7/3"
strvar2 = strvar.replace(strvar1,str(res1))
print(strvar2) # 30-7/3
# 匹配出 7/3
obj = re.search(r"d+[*/]d+",strvar2)
strvar3 = obj.group()
print(strvar3) # 7/3
# 按照/号分隔,算出除法结果
n1,n2 = strvar3.split("/")
res2 = int(n1)/int(n2)
print(res2)
# 对字符串进行替换
strvar4 = strvar2.replace(strvar3,str(res2))
print(strvar4)
# 通过-号进行最后的分隔,算出最后的结果.
n1,n2 = strvar4.split("-")
res_finally = float(n1) - float(n2)
print(res_finally)
当不清楚字符串中含有什么内容的时候,用.*?进行取代
1.反向引用
# 1 代表反向引用,将第一个括号匹配的字符串,在1位置处在引用一次
lst = re.findall(r"<(.*?)>(.*?)<(/1)>",strvar)
print(lst) # [('div', '明天就放假了,很开心', '/div')]
# 1 代表第一个括号 2代表第二个括号
strvar = "a1b2cab"
obj = re.search(r"(.*?)d(.*?)d(.*?)12",strvar)
print(obj)
# 返回匹配到的字符串
res = obj.group()
print(res)
# 返回匹配到的分组内容
res = obj.groups()
print(res)
2.命名分组
"""
# 2.命名分组 (给小组命名)
3) (?P<组名>正则表达式) 给这个组起一个名字
4) (?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置
"""
# 方法一
strvar = "a1b2cab"
obj = re.search(r"(?P<tag1>.*?)d(?P<tag2>.*?)d(?P<tag3>.*?)12",strvar)
print(obj.group()) # a1b2cab
# 方法二
strvar = "a1b2cab"
obj = re.search(r"(?P<tag1>.*?)d(?P<tag2>.*?)d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar)
print(obj.group()) # a1b2cab