Python正则表达式re模块
参考:https://www.cnblogs.com/cute/p/9186208.html
老男孩苑昊老师: http://www.cnblogs.com/yuanchenqi/articles/5732581.html
廖雪峰老师: https://www.liaoxuefeng.com/wiki/1016959663602400/1017639890281664
https://www.cnblogs.com/hanmk/p/9143514.html
爬虫部分的re模块使用:https://www.cnblogs.com/XJT2018/p/10312830.html
re模块(* * * * *)
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
正则 就是对字符串进行模糊匹配
字符匹配(普通字符,元字符):
1、普通字符:大多数字符和字母都会和自身匹配
>>> re.findall('alvin','yuanaleSxalexwupeiqi')
['alvin']
2、元字符: . ^ $ * + ? { } [ ] | ( ) 的详细解释:
^
匹配行首,以 xxx为开头
$
匹配行尾,以xxx结尾。
转义字符,如果要匹配本身,需要使用再次转义:
\
。
一些特殊字符:
d:匹配:[0-9] D:匹配:[^0-9] s:匹配:任何空白符,即:[ fv] S:匹配:任何非空白符,即:[^ fv] w:匹配:[a-zA-Z0-9_ ] W:匹配:[^a-zA-Z0-9_ ]
*
匹配前一个字符或子表达式出现 0次或多次。
+
匹配前一个字符或子表达式出现 1次或多次。
?
(1) 匹配前一个字符或子表达式出现 0次或1次。
(2) 跟在 * 或 + 后面表示非贪婪匹配:
*? 匹配0个
+? 匹配1个
import re # 贪婪模式,会尽量多地去匹配 r1 = re.compile(r'ab+') s1 = 'abbb' print(re.findall(r1,s1)) #['abbb'] # 非贪婪模式,会尽量少地去匹配 r2 = re.compile(r'ab+?') s2 = 'abbb' print(re.findall(r2,s2)) #['ab']
{}
匹配前一个字符或子表达式出现指定次数:
-
{0,}
:0次或多次,相当于*
-
{1,}
:1次或多次,相当于+
-
{0,1}
:0次或1次,相当于?
-
{m,n}
:m次到n次(m <= n)
import re ret=re.findall('a..in','helloalvin') print(ret)#['alvin'] ret=re.findall('^a...n','alvinhelloawwwn') print(ret)#['alvin'] ret=re.findall('a...n$','alvinhelloawwwn') print(ret)#['awwwn'] ret=re.findall('a...n$','alvinhelloawwwn') print(ret)#['awwwn'] ret=re.findall('abc*','abcccc')#贪婪匹配[0,+oo] print(ret)#['abcccc'] ret=re.findall('abc+','abccc')#[1,+oo] print(ret)#['abccc'] ret=re.findall('abc?','abccc')#[0,1] print(ret)#['abc'] ret=re.findall('abc{1,4}','abccc') print(ret)#['abccc'] 贪婪匹配
注意:前面的 *,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配(非贪婪匹配)
ret=re.findall('abc*?','abcccccc') print(ret)#['ab']
跟着教程敲代码练习:

""" 第一类元字符 . ^ $ * + ? {}""" import re """ . 匹配除了 之外的任意字符,一个 . 只能匹配一个字符 """ re.findall("alex","djkalfjioealexieou") ##['alex'] re.findall("a..x",'jowutojoauixuoero') #['auix'] re.findall("a...x",'jowutojoauixuoero') #[] """ ^ 开头匹配 """ re.findall("^a...x",'jowutojoauixuoero') #[] re.findall("^j..u",'jowutojowuixuoero') #['jowu'] re.findall("j..u",'jowutojowuixuoero') #['jowu', 'jowu'] """ $ 结尾匹配 """ re.findall("j..u$",'jowutojowuixuoejrou') #['jrou'] re.findall("j..u$",'jowutojowuixuoejrou$') #[] """ * 紧挨着的字符 匹配0~无穷次 """ """ + 紧挨着的字符 匹配1~无穷次 """ re.findall("alex*","uoghkalexxx") #['alexxx'] re.findall("alex+","uoghkalexxx") #['alexxx'] re.findall("alex*","uoghkale") #['ale'] re.findall("alex+","uoghkale") #[] """ ? 紧挨着的字符 匹配0~1 """ re.findall("alex?","uoghkale") #['ale'] re.findall("alex?","uoghkalex") #['alex'] re.findall("alex?","uoghkalexxxx") #['alex'] """ {} 是上面 * + ? 的集合,并且可自定义 {0,} <===> * {1,} <===> + {0,1} <===> ? {1,6} 1 2 3 4 5 6 都可以 """ re.findall("alex{6}","uoghkalexxxxxx") #['alexxxxxx'] re.findall("alex{0,6}","uoghkalexxx") #['alexxx'] re.findall("alex{0,6}","uoghkale") #['ale'] re.findall("alex{0,1}","uoghkale") #['ale'] re.findall("alex{0,1}","uoghkalex") #['alex'] # 惰性匹配 在元字符后面加上 ? re.findall("alex*?","uoghkalexxxx") #['ale'] re.findall("alex+?","uoghkalexxxx") #['alex'] re.findall("alex+","uoghkalexxxx") #['alexxxx']
元字符之字符集[]:
(1) 常用来指定一个字符集,如[abc]
匹配:a或b或c
(2) 元字符. * ? + ^ $ 在[]
中不起所用,比如:[a+]匹配:a或+
但注意:在方括号中:要匹配转义符“”本身,要用:\
;要匹配方括号开头的^
符本身,要用:^
;要匹配-
字符,需要用:-
(3) 补集匹配:[^a]
,匹配非a的一个字符,^在[ ]中表示取非
(4) 匹配连续字符:[a-zA-Z0-9]
,匹配大小写英文字母和数字
#--------------------------------------------字符集[] ret=re.findall('a[bc]d','acd') print(ret)#['acd'] ret=re.findall('[a-z]','acd') print(ret)#['a', 'c', 'd'] ret=re.findall('[.*+]','a.cd+') print(ret)#['.', '+'] #在字符集里有功能的符号: - ^ ret=re.findall('[1-9]','45dha3') print(ret)#['4', '5', '3'] ret=re.findall('[^ab]','45bdha3') print(ret)#['4', '5', 'd', 'h', '3'] ret=re.findall('[d]','45bdha3') print(ret)#['4', '5', '3']
跟着教程敲代码练习:

""" [] 中:^ 非 ,- 表示从。。到。。 a-z 所有小写字母, 转义 ( 就表示左括号。 其他的元字符失去意义,如 * 不表示(0-无穷),()就只是表示括号 """ ret = re.findall('a[bc]d', 'acd') # 匹配 abd 或 acd print(ret) # ['acd'] ret = re.findall('[a-z]', 'acd') #一个字符 从a到z print(ret) # ['a', 'c', 'd'] ret = re.findall('[.*+]', 'a.cd+') #* 失去特殊意义 就表示一个 * print(ret) # ['.', '+'] # 在字符集里有功能的符号: - ^ ret = re.findall('[1-9]', '45dha3') print(ret) # ['4', '5', '3'] ret = re.findall('[^ab]', '45bdha3') print(ret) # ['4', '5', 'd', 'h', '3'] ret = re.findall('[d]', '45bdha3') print(ret) # ['4', '5', '3']
# 一个特殊案例:匹配表达式里面 最内层括号(13-6) re.findall("([^()]*)","12+(34*6+2-5*(13-6))") #['(13-6)']
元字符之转义符
反斜杠后边跟元字符去除特殊功能,比如 .
反斜杠后边跟普通字符实现特殊功能,比如 d
- d 匹配任何十进制数;它相当于类 [0-9]。
- D 匹配任何非数字字符;它相当于类 [^0-9]。
- s 匹配任何空白字符;它相当于类 [ fv]。
- S 匹配任何非空白字符;它相当于类 [^ fv]。
- w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
- W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
- 匹配一个特殊字符边界,比如空格 ,&,#等
ret=re.findall('I','I am LIST') print(ret)#[] ret=re.findall(r'I','I am LIST') print(ret)#['I'] r'I' 其中 r=raw 表示原始的 未经处理的 re.findall(r'I','I am LIST') #r'I' 要先经过Python解释器编译 然后传递给re模块,re模块处理 匹配到 空格
现在我们聊一聊 ,先看下面两个匹配:
#-----------------------------eg1: import re ret=re.findall('cl','abcle') print(ret)#[] ret=re.findall('c\l','abcle') print(ret)#[] ret=re.findall('c\\l','abcle') print(ret)#['c\l'] ret=re.findall(r'c\l','abcle') print(ret)#['c\l'] #-----------------------------eg2: #之所以选择是因为在ASCII表中是有意义的 m = re.findall('blow', 'blow') print(m) m = re.findall(r'blow', 'blow') print(m)
由于Python的字符串本身也用 转义,所以要特别注意:
s = 'ABC\-001' # Python的字符串 # 对应的正则表达式字符串变成: # 'ABC-001'
因此我们强烈建议使用Python的 r
前缀,就不用考虑转义的问题了:
s = r'ABC-001' # Python的字符串 # 对应的正则表达式字符串不变: # 'ABC-001'
元字符之分组 ()
(?P<分组名>d+) 有名分组 可以通过ret.group('分组名') 取得匹配结果
m = re.findall(r'(ad)+', 'add') print(m) #ad ret=re.search('(?P<id>d{2})/(?P<name>w{3})','23/com') print(ret.group()) #23/com print(ret.group('id')) #23 ##'(?P<id>d{2})/(?P<name>w{3})' ?P<id> 分组 组名为ip, d{2} 匹配后面两位整数 #(?P<name>w{3}) ?P<id> 分组 组名为name,w{3} 匹配3位 大小写字母 数字 下划线
>>> re.search(r'<a.*>(.*)</a>.*<p>(.*)</p>',s).group(1) '更多' >>> re.search(r'<a.*>(.*)</a>.*<p>(.*)</p>',s).group(2) 'dfsl' >>> ss = re.search(r'<a.*>(?P<txt>.*)</a>.*<p>(?P<txt2>.*)</p>',s) >>> ss.group('txt') '更多' >>> ss.group('txt2')
练习:

>>> re.findall(r'(abc)+','adklnvkaj45d6kasdfeabcwoibcfabcabcabcdf') ['abc', 'abc'] >>> re.findall(r'abc+','adklnvkaj45d6kasdfeabcwoibcfabcabcabcdf') ['abc', 'abc', 'abc', 'abc'] >>> re.findall(r'(abc)+','abcabcabcabc') ['abc'] >>> re.findall(r'(abc)*','abcabcabcabc') ['abc', ''] >>> re.findall(r'(ab)+','abcabcabcabc') ['ab', 'ab', 'ab', 'ab'] >>> re.findall(r'(abc)+','abcabcabcabc') ['abc'] >>> re.findall(r'(abc)+','abcccccc') ['abc'] >>> re.findall(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56') ['xiong', 'wang', 'zhang', 'sun'] >>> re.search(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56') <_sre.SRE_Match object; span=(0, 7), match='xiong26'> >>> re.search(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56').group() 'xiong26' >>> re.search(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56').group("name") 'xiong' >>> re.search(r'(?P<name>[a-z]+)(?P<age>d+)','xiong26wang33zhang23sun56').group("name") 'xiong' >>> re.search(r'(?P<name>[a-z]+)(?P<age>d+)','xiong26wang33zhang23sun56').group("age") '26'
元字符之|
ret=re.search('(ab)|d','rabhdg8sd') print(ret.group())#ab
re模块下的常用方法
# 1 re.findall('a', 'alvin yuan') # 返回所有满足匹配条件的结果,放在列表里 # 2 re.search('a', 'alvin yuan').group() # 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 # 3 re.match('a', 'abc').group() # 同search,不过要在字符串开始处进行匹配,相当于re.search('^','') # 4 ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 print(ret) # ['', '', 'cd'] # 5 ret = re.sub('d', 'A', 'alvin5yuan6', 1) ## 替换 数字 替换为 A , 只替换第一个 print(ret) # alvinAyuan6 ret = re.subn('d', 'A', 'alvin5yuan6') #将替换结果 和 替换个数 返回为一个元组 print(ret) # ('alvinAyuanA', 2) # 6 obj = re.compile('d{3}') ## 编译,如果使用多次匹配规则 效率就体现出来了 ret = obj.search('abc123eeee') print(ret.group()) # 123
处理大量数据,匹配结果返回一个迭代器
import re ret=re.finditer('d','ds3sy4784a') print(ret) #<callable_iterator object at 0x10195f940> print(next(ret).group()) print(next(ret).group())
注意:
ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果分组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['www.oldboy.com']
补充练习题:

>>> import re >>> re.findall('d+','nka15640-8dasgwe-96dagv-6') ['15640', '8', '96', '6'] >>> re.findall('^d+','nka15640-8dasgwe-96dagv-6') [] >>> re.findall('[^-]d+','nka15640-8dasgwe-96dagv-6') ['a15640', '96'] >>> re.findall('d{3}s+d{3,8}','sdfag123 7845agewgv') ['123 7845'] >>> re.findall('d+@$','1351655382@qq.com') [] >>> re.findall('d+','1351655382@qq.com') ['1351655382'] >>> re.findall(r'ka|b','adklnvkj45d6kaewoib') ['ka', 'b'] >>> re.findall(r'ka|b','adklnvkj45d6ksdfewoibfadf') ['b'] >>> re.findall(r'ka|bc','adklnvkaj45d6kasdfewoibcfadf') ['ka', 'ka', 'bc'] >>> re.findall(r'(abc)+','adklnvkaj45d6kasdfeabcwoibcfabcabcabcdf') ['abc', 'abc'] >>> re.findall(r'abc+','adklnvkaj45d6kasdfeabcwoibcfabcabcabcdf') ['abc', 'abc', 'abc', 'abc'] >>> re.findall(r'(abc)+','abcabcabcabc') ['abc'] >>> re.findall(r'(abc)*','abcabcabcabc') ['abc', ''] >>> re.findall(r'(ab)+','abcabcabcabc') ['ab', 'ab', 'ab', 'ab'] >>> re.findall(r'(abc)+','abcabcabcabc') ['abc'] >>> re.findall(r'(abc)+','abcccccc') ['abc'] >>> re.findall(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56') ['xiong', 'wang', 'zhang', 'sun'] >>> re.search(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56') <_sre.SRE_Match object; span=(0, 7), match='xiong26'> >>> re.search(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56').group() 'xiong26' >>> re.search(r'(?P<name>[a-z]+)d+','xiong26wang33zhang23sun56').group("name") 'xiong' >>> re.search(r'(?P<name>[a-z]+)(?P<age>d+)','xiong26wang33zhang23sun56').group("name") 'xiong' >>> re.search(r'(?P<name>[a-z]+)(?P<age>d+)','xiong26wang33zhang23sun56').group("age") '26' >>> re.findall('(ab)|d','rabhdg8sd') ['ab', ''] >>> re.findall('(ab)|d+','rabhdg8sd') ['ab', ''] >>> re.findall('(ab)|d+','rab632hdg8sd') ['ab', '', ''] >>> re.findall('(ab)|d','rab632hdg8sd') ['ab', '', '', '', ''] >>> re.findall('(ab)|d+','rab632hdg8sd') ['ab', '', ''] >>> re.findall('(ab).*d+','rab632hdg8sd') ['ab'] >>> re.match('a', 'abc').group() 'a' >>> re.match('a', 'abcadfa').group() 'a' >>> ####################split分割 >>> re.split(' ','hello world xiong') ['hello', 'world', 'xiong'] >>> re.split('[ |]','hello world|xiong') ['hello', 'world', 'xiong'] >>> re.split('[ab]','vnklaouojbouhg') ['vnkl', 'ouoj', 'ouhg'] >>> re.split('[ab]','auouabuobuo') ['', 'uou', '', 'uo', 'uo'] >>> re.split('[ab]','asdabcd') ['', 'sd', '', 'cd'] >>> re.split('[ab]','abc') ['', '', 'c'] >>> >>>############# '替换' >>> re.sub('d+','A','as451da23bc23d5dae') 'asAdaAbcAdAdae' >>> re.sub('d','A','as451da23bc23d5dae') 'asAAAdaAAbcAAdAdae' >>> re.sub('d','A','as451da23bc23d5dae',3) 'asAAAda23bc23d5dae' >>> re.sub('d','A','as451da23bc23d5dae',2) 'asAA1da23bc23d5dae' >>> re.subn('d','A','as451da23bc23d5dae') ('asAAAdaAAbcAAdAdae', 8) >>> ###########compile编译 >>> com = re.compile("d+") >>> com.findall("uoihja37jdaogj230ldaoje") ['37', '230'] >>> >>> re.findall("d","af7nka89wejojk03oajag") ['7', '8', '9', '0', '3'] >>> re.finditer("d","af7nka89wejojk03oajag") <callable_iterator object at 0x000001E1D2836BE0> >>> ret = re.finditer("d","af7nka89wejojk03oajag") >>> ret.__next__() <_sre.SRE_Match object; span=(2, 3), match='7'> >>> ret.__next__().group() '8' >>>#############结果返回为一个迭代器 >>> ret = re.finditer("www.(baidu|163).com","af7nkawww.baidu.com89wejojk03oajag") >>> re.finditer("www.(baidu|163).com","af7nkawww.baidu.com89wejojk03oajag") <callable_iterator object at 0x000001E1D2836B00> ###################匹配结果优先返回为匹配到的分组内容 >>> re.findall("www.(baidu|163).com","af7nkawww.baidu.com89wejojk03oajag") ['baidu'] >>> re.findall("www.(?:baidu|163).com","af7nkawww.baidu.com89wejojk03oajag") ['www.baidu.com']
补充1:

import re print(re.findall("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")) print(re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")) print(re.search(r"<(w+)>w+</1>","<h1>hello</h1>"))
补充2:

#匹配出所有的整数 import re #ret=re.findall(r"d+{0}]","1-2*(60+(-40.35/5)-(-4*3))") ret=re.findall(r"-?d+.d*|(-?d+)","1-2*(60+(-40.35/5)-(-4*3))") ret.remove("") print(ret)