XJT2018

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

 

 

 

分类:

技术点:

相关文章: