Python正则表达式 re模块

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:匹配:任何空白符,即:[\t\n\r\f\v]

\S:匹配:任何非空白符,即:[^\t\n\r\f\v]

\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

""" . 匹配除了 \n 之外的任意字符,一个 . 只能匹配一个字符 """
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  匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
  • \S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
  • \w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
  • \W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
  • \b  匹配一个特殊字符边界,比如空格 ,&,#等
ret=re.findall('I\b','I am LIST')
print(ret)#[]
ret=re.findall(r'I\b','I am LIST')
print(ret)#['I']

r'I\b'   其中 r=raw 表示原始的 未经处理的
re.findall(r'I\b','I am LIST')   #r'I\b'  要先经过Python解释器编译 然后传递给re模块,re模块处理 \b 匹配到 空格

现在我们聊一聊 \ ,先看下面两个匹配:

#-----------------------------eg1:
import re
ret=re.findall('c\l','abc\le')
print(ret)#[]
ret=re.findall('c\\l','abc\le')
print(ret)#[]
ret=re.findall('c\\\\l','abc\le')
print(ret)#['c\\l']
ret=re.findall(r'c\\l','abc\le')
print(ret)#['c\\l']
 
#-----------------------------eg2:
#之所以选择\b是因为\b在ASCII表中是有意义的
m = re.findall('\bblow', 'blow')
print(m)
m = re.findall(r'\bblow', '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'
cmd执行

元字符之|

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>"))
View Code

补充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)
View Code

 

 

 

posted @ 2019-05-15 21:18  XJT2019  阅读(326)  评论(0编辑  收藏  举报