day19.re正则表达式
一、单个字符的匹配
import re
1、findall(正则表达式,字符串)
# 把符合正则表达式的字符串存在列表中返回
2、预定义字符串
# \d 匹配数字 strvar = "sdfsdf*(&*(&(2ui3" lst = re.findall("\d",strvar) print(lst) # \D 匹配非数字 strvar = "sdfsdf*(&*(&(2ui3" lst = re.findall("\D",strvar) print(lst) # \w 匹配字母数字下划线 strvar = "sadf*)(*_)456你你好" lst = re.findall("\w",strvar) print(lst) # \W 匹配非字母或数字或下划线 strvar = "sadf*)(*_)456你你好" lst = re.findall("\W",strvar) print(lst) # \s 匹配任意的空白符 (\n \t \r ' ') strvar = " " lst = re.findall("\s",strvar) print(lst) # \S 匹配任意非空白符 strvar = " abdd " lst = re.findall("\S",strvar) print(lst) # \n 匹配一个换行符 strvar = """ """ lst = re.findall(r"\n",strvar) print(lst) # \t 匹配一个制表符 strvar = """ """ lst = re.findall(r"\t",strvar) print(lst)
3、字符组[]
# 必须从字符组列举出来的字符当中抽取,默认一个,如果没有返回空
strvar = "abpoiuc" lst = re.findall("[abc]",strvar) print(lst) # ['a', 'b', 'c']
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
4、- 代表到,代表的是范围
# 0-9 0到9这么多的数字 print(re.findall('a[0-9]b','a1b a2b a3b acb ayb')) # a1b a2b a3b
# a-g => abcdefg print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) # acb adb print(re.findall('a[a-g]b','a1b a2b a3b acb ayb adb')) # acb adb
# a-z => 26个小写字母 print(re.findall('a[a-z]b','a1b a2b a3b acb ayb adb')) # acb ayb adb
# A-G => ABCDEFG print(re.findall('a[ABCDEFG]b','a1b a2b a3b aAb aDb aYb')) #aAb aDb print(re.findall('a[A-G]b','a1b a2b a3b aAb aDb aYb')) #aAb aDb # A-Z=> 26个大写字母 print(re.findall('a[A-Z]b','a1b a2b a3b aAb aDb aYb')) #aAb aDb aYb
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_ba@b aab aAb aWb aqba1b')) # aab aAb aWb aqb a1b
print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) #a1/b
5、^ 除了 , 在字符组当中,开头的位置使用
print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) #a%b a&b
# 如果想要匹配^ - 需要前面加上\进行转义 lst = re.findall("a[\^\-]b","a+b a-b a^b") print(lst) # ['a-b', 'a^b']
6、匹配 \
"""\b 本身也是转义字符 : 退格(把光标向左移动一位)""" lst = re.findall(r"a\\b",r"a\b") print(lst[0])
二、正则表达式-多个字符的匹配
import re
1、量词
1.1 ? 匹配0个或者1个
print(re.findall('a?b','abbzab abb aab')) # ab b ab ab b ab
1.2 + 匹配1个或者多个
print(re.findall('a+b','b ab aaaaaab abb')) # ab aaaaaab ab
1.3 * 匹配0个或者多个
print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b
1.4 {m,n} 匹配m个至n个
# 1 <= x <= 3 print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # aaab ab aab ab aab # {2,} 至少2次 print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab # {2} 必须2次 print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab
1.5 贪婪匹配和非贪婪匹配
""" 贪婪匹配 : 默认向更多次数匹配(回溯算法) 非贪婪匹配 : 默认向更少次数匹配 在量词的后面接? .?? .+? .*? {4,}? 回溯算法 : 从左向右进行匹配,直到匹配到最后,再也找不到了,回头,找最后一个(递归) . 匹配任意字符,除了换行符\n """
import re strvar = "刘能和刘老根和刘铁柱子111子222" lst = re.findall("刘.",strvar) # ['刘能', '刘老', '刘铁'] print(lst) lst = re.findall("刘.?",strvar) # ['刘能', '刘老', '刘铁'] print(lst) lst = re.findall("刘.+",strvar) # ['刘能和刘老根和刘铁柱子111子222'] print(lst) lst = re.findall("刘.*",strvar) # ['刘能和刘老根和刘铁柱子111子222'] print(lst) lst = re.findall("刘.{4,}子",strvar) # ['刘能和刘老根和刘铁柱子111子'] print(lst)
# 非贪婪匹配 lst = re.findall("刘.??",strvar) # ['刘', '刘', '刘'] print(lst) lst = re.findall("刘.+?",strvar) # 刘能 刘老 刘铁 print(lst) lst = re.findall("刘.*?",strvar) # ['刘', '刘', '刘'] print(lst) lst = re.findall("刘.{4,}?子",strvar) # ['刘能和刘老根和刘铁柱子'] print(lst)
三、边界符 \b
""" \b 本身也是转义字符 : 退格(把光标向左移动一位) word 右边界: d\b 左边界: \bw """
1、右边界
# 右边界 strvar = "word pwd scf" lst = re.findall(r"d\b",strvar) print(lst) # [d,d] lst = re.findall(r".*d\b",strvar) print(lst) # ['word pwd'] lst = re.findall(r".*?d\b",strvar) print(lst) # ['word', ' pwd']
2、左边界
lst = re.findall(r"\bw",strvar) print(lst) # 要所有w开头的单词 lst = re.findall(r"\bw.*",strvar) print(lst) # ['word pwd scf'] lst = re.findall(r"\bw.*?",strvar) print(lst) # ['w'] lst = re.findall(r"\bw.* ",strvar) print(lst) # ['word pwd '] lst = re.findall(r"\bw.*? ",strvar) print(lst) # ['word '] # lst = re.findall(r"w\S*",strvar) # print(lst) # \S 匹配的是非空白符 lst = re.findall(r"\bw\S*",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
五、正则表达式-匹配分组 ()
import re
1、分组练习(用圆括号)
print(re.findall('.*?_good','aa_good bb_good cc_good')) # () 优先显示括号里面的内容 print(re.findall('(.*?)_good','aa_good bb_good cc_good')) # ?: 取消显示括号里面的内容 print(re.findall('(?:.*?)_good','aa_good bb_good cc_good'))
2、 | 或
# | 代表或 , a|b 匹配字符a 或者 匹配字符b . 把字符串长的写在前面,字符串短的写在后面
strvar = "abcdefg" lst = re.findall("a|b",strvar) print(lst) """在使用|的时候,把不容易匹配到的字符串放到前面,把容易匹配到的放到后面""" strvar = "abciuiuabcdwerewr" lst = re.findall("abc|abcd",strvar) lst = re.findall("abcd|abc",strvar) print(lst)
3、练习
""" . 除了\n,匹配所有字符 \. 代表的.这个字符本身,不转义 """
strvar = ".34 .... 78. 78.12 56.3 .3 .4 .5 " # 匹配小数 lst = re.findall(r"\d+\.\d+",strvar) print(lst) # 匹配小数和整数 lst = re.findall(r"\d+\.\d+|\d+",strvar) print(lst) # 分组来表达小数和整数 lst = re.findall(r"\d+(\.\d+)?",strvar) print(lst) lst = re.findall(r"\d+(?:\.\d+)?",strvar) print(lst) # ['34', '78', '78.12', '56.3', '3', '4', '5'] # 匹配135或171的手机号 strvar = "13566668888 17166668888" lst = re.findall(r"(?:135|171)\d{8}",strvar) print(lst) # 用^$卡死长度,只能是一个手机号,不能是多个 strvar = "13566668888" lst = re.findall(r"^(?:135|171)\d{8}$",strvar) print(lst) # 匹配www.baidu.com 或者 www.oldboy.com strvar = "www.baidu.com www.lagou.com www.oldboy.com" lst = re.findall(r"(?:www).(?:baidu|oldboy).(?:com)",strvar) print(lst)
六、search
""" findall 是把所有符合条件的内容都匹配出来放到列表里 不能够把匹配到的结果和分组当中的内容显示在同一个界面当中 search 按照正则表达式,把第一次匹配到的内容返回出来,返回的是对象 能够把匹配到的结果和分组当中的内容显示在同一个界面当中 对象.group 返回的是匹配到的结果 对象.groups 返回的是括号分组里面的内容 如果匹配不到内容,返回的是None ,无法调用group 或者groups方法的 """
1、search的用法
strvar = "www.baidu.com www.lagou.com www.taobao.com" obj = re.search(r"www\.(baidu|taobao)\.(com)",strvar) # 返回的是匹配到的结果 res = obj.group() print(res) # 通过group和下标可以获取到括号的内容(了解) print(obj.group(1)) print(obj.group(2)) # 返回的是括号分组里面的内容 res = obj.groups() print(res)
七、计算 “5*6-7/3” 的结果
# "5*6-7/3" 匹配 5*6 或者 7/3 算出最后的结果 strvar = "5*6-7/3" # 匹配5*6 obj = re.search(r"\d+[*/]\d+",strvar) print(obj) strvar1 = obj.group() print(strvar1,type(strvar1),"<===>") # 5*6 <class 'str'> <===> # 计算5*6 num1,num2 = strvar1.split("*") print(num1,num2) strvar2 = str(int(num1) * int(num2)) print(strvar2 ,type(strvar2)) # "30" # 替换5*6 为字符串30 strvar3 = strvar.replace(strvar1,strvar2) print(strvar3 , type(strvar3)) # 30-7/3 <class 'str'> # 匹配7/3 obj = re.search(r"\d+[*/]\d+",strvar3) print(obj) strvar4 = obj.group() print(strvar4) # 7/3 # 计算7/3 num1,num2 = strvar4.split("/") strvar5 = str(int(num1) / int(num2)) print(strvar5 , type(strvar5)) # 替换7/3 为字符串2.333333333333 strvar6 = strvar3.replace(strvar4,strvar5) print(strvar6 , type(strvar6)) # 计算 30-2.3333333333333335 得出最后的结果 num1,num2 = strvar6.split("-") res = float(num1) - float(num2) print(res)
八、命名分组
import re strvar = "<div>今天天气不错~</div>" lst = re.findall("<(.*?)>(.*?)<(.*?)>",strvar) print(lst)
1、反向引用
# 在匹配到的值,在引用一次
'''\1 把第一个小括号里面的内容,拿出来在匹配一下''' lst = re.findall(r"<(.*?)>(.*?)<(/\1)>",strvar) print(lst) # \1 代表反向引用第一个括号内容 \2代表反向引用第二个括号内容 strvar = "a1b2cab" # strvar = "f1z2pfz" obj = re.search(r"(.*?)\d(.*?)\d(.*?)\1\2",strvar) print(obj) # 获取匹配到的内容 res1 = obj.group() print(res1) # 获取分组里面的内容 res2 = obj.groups() print(res2)
2、命名分组
""" 3) (?P<组名>正则表达式) 给这个组起一个名字 4) (?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置 """
方法一:
strvar = "a1b2cab" obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)\1\2",strvar) # 获取匹配到的内容 res1 = obj.group() print(res1) # 获取分组里面的内容 res2 = obj.groups() print(res2)
方法二:
strvar = "a1b2cab" obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar) # 获取匹配到的内容 res1 = obj.group() print(res1) # 获取分组里面的内容 res2 = obj.groups() print(res2)
九、正则函数
1、search
# 通过正则匹配出第一个对象返回,通过group取出对象中的值
strvar = "1+2 3*4" obj = re.search("\d+(.*?)\d+",strvar) print(obj) # 返回匹配到的内容(匹配到一个就返回) res = obj.group() print(res) # 返回分组里面的内容,类型是元组 tup = obj.groups() print(tup[0])
2、match
# 验证用户输入内容(了解)
"""当search函数里面的正则表达式前面加上^ 等价于 math的用法""" strvar = "a13566668888" # strvar = "13566668888" obj = re.search("^\d+",strvar) print(obj) # print(obj.group()) obj = re.match("\d+",strvar) print(obj) # print(obj.group())
3、split 切割
strvar = "kxq|xboyww&jack%ritian" res = re.split("[|&%]",strvar) print(res) strvar = "kxq234234xboyww6786jack78967896ritian" # [0-9] <=> \d res = re.split("\d+",strvar) # res = re.split("[0-9]+",strvar) print(res)
4、sub 替换
"""sub(正则,要替换的字符,原字符串[,次数])""" strvar = "kxq|xboyww&jack%ritian" res = re.sub("[|&%]","-",strvar) print(res) strvar = "kxq|xboyww&jack%ritian" res = re.sub("[|&%]","-",strvar,2) print(res)
# 传统replace替换的写法 strvar = "kxq|xboyww&jack%ritian" strvar = strvar.replace("|","-").replace("&","-").replace("%","-") print(strvar)
5、subn 替换 (用法和sub一样,区别在于返回的是元组 (结果,次数) )
strvar = "kxq|xboyww&jack%ritian" res = re.subn("[|&%]","-",strvar) res = re.subn("[|&%]","-",strvar,1) print(res)
6、finditer 匹配字符串中相应内容,返回迭代器[迭代器中包含的是对象]
from collections import Iterator , Iterable strvar = "jkasdfjkadfjk1234asfj2342kfa" it = re.finditer("\d+",strvar) print(isinstance(it,Iterator)) # 获取迭代器里面的内容 for i in it: print(i.group())
7、compile 指定一个统一的匹配规则
""" 正常情况下,正则表达式编译一次,执行一次. 如果想要编译一次,多次使用的话,使用compile compile 可以编译一次,终身受益.节省系统的资源 """
strvar = "jksdjdfsj72343789asdfaj234" pattern = re.compile("\d+") print(pattern) lst = pattern.findall(strvar) print(lst) obj = pattern.search(strvar) print(obj.group())
8、正则表达式修饰符
8.1 re.I 使匹配对大小写不敏感
# re.I 使匹配对大小写不敏感 strvar = "<h1>72347923489</H1>" pattern = re.compile(r"<h1>(.*?)</h1>",flags=re.I) obj = pattern.search(strvar) print(obj) print(obj.group())
8.2 re.M 使每一行都能够单独匹配(多行),影响 ^ 和 $
strvar = """<h1>72347923489</H1> <p>72347923489</p> <li>72347923489</li> """ pattern = re.compile("^<.*?>(?:.*?)<.*?>$",flags=re.M) lst = pattern.findall(strvar) print(lst)
8.3 re.S 使 . 匹配包括换行在内的所有字符
strar = """give 1234234234mefive """ pattern = re.compile("(.*?)mefive",flags=re.S) obj = pattern.search(strar) print(obj) print(obj.group())
8.4 可以加多个修饰符 通过| 拼接
""" pattern = re.compile("(.*?)mefive",flags=re.S|re.I|re.M) """
十、练习
1.匹配整数或者小数(包括正数和负数)
[+-]?\d+(\.\d+)?
2、匹配年月日日期 格式 2018-12-31 2018-1-12 2018-1-1 2018-1-10
([1-9]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|1[0-9]|2[0-9]|3[01])
([1-9]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])
3、匹配qq号 5-12 首字符没有0
[1-9]\d{4,11}
4、11位的电话号码
^1[3-9]\d{9}$
5、长度为8-10位的用户密码 : 包含数字字母下划线
\w{8,10}
6、匹配验证码:4位数字字母组成的
[0-9a-zA-Z]{4}
[\da-zA-Z]{4}
7、匹配邮箱地址 邮箱规则 123463922@qq.com 123@abc.com.cn
7.1、@之前必须有内容且只能是字母,数字,下划线(_),减号(-),点(.)
[\w\-\.]+
7.2、@符号后面是字母,数字,减号(-),保留121@qq.com.cn 的可能
@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)?
7.3、最后一个.之后是字母数字,长度为2~6
\.[a-zA-Z\d]{2,6}
[\w\-\.]+@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)?\.[a-zA-Z\d]{2,6}
8、从类似<a>wahaha</a> <b>banana</b><h1>qqxing</h1><h1>q</h1>这样的字符串中
1)匹配出 wahaha,banana,qqxing 内容。
"<.*?>(.*?)<.*?>"
2)匹配出 a,b,h1这样的内容
"<(.*?)>.*?<.*?>"