Python攻克之路-re模块

re模块
描述:正则表达式(或RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,产通过re模块实现,正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行.正则提供是模糊匹配.
字符串提供的方式是完成匹配,如ll就是对应ll

In [19]: s='hello world'
In [20]: s.find('ll')
Out[20]: 2               #不是个数,是位置
In [21]: s.find('llo')
Out[21]: 2
In [22]: s.find('h')
Out[22]: 0
In [23]: s.replace('ll','vv')
Out[23]: 'hevvo world'

  

字符匹配(普通字符、元字符)
普通字符:大多数字符和字母都会和自身匹配

In [28]: re.findall('reid','aljflsdjreiddsfjls') ##完全匹配,可以不使用正则
Out[28]: ['reid']

  

1.元字符:. ^ $ * + ? [] {} | () \
正则提供模糊匹配

In [26]: import re
In [27]: re.findall('w\w{2}l','hello world')  #规则   内容  flags(标志位,可以修改默认规则,如不匹配换行符这个规则,可以修改)
Out[27]: ['worl']

  

.点:通配符,指匹配单个所有字符,不把匹配换行符\n

In [29]: re.findall('w..l','hello world')
Out[29]: ['worl']

  

^尖括号:以最开始的位置匹配

In [5]: re.findall('he..o','hjsdflhello')
Out[5]: ['hello']
In [6]: re.findall('^he..o','hjsdflhello')
Out[6]: []
In [8]: re.findall('^h...o','hjsdolhello')
Out[8]: ['hjsdo']

  

$:以结尾位置来匹配

In [10]: re.findall('r..d','lkjlkfjsdlkjfreidljlkj')
Out[10]: ['reid']
In [11]: re.findall('r..d$','lkjlkfjsdlkjfreidljlkj')
Out[11]: []
In [12]: re.findall('r..d$','lkjlkfjsdlkjfreidljlkjreid')
Out[12]: ['reid']

  

*:重复匹配(.*点表示任意多个字符,*重复前面任意多次,重复任意字符多次,0到无穷)

In [15]: re.findall('b*b','youbbbbbbblsdjflajf')
Out[15]: ['bbbbbbb']
In [18]: re.findall('jf*','youbbbbbbblsdlajf')      #*可以匹配0次
Out[18]: ['jf']

In [16]: re.findall('.*','youbbbbbbblsdjflajf')
Out[16]: ['youbbbbbbblsdjflajf', '']            #匹配所有,而且空的也是一个

  

+:重复匹配前一个字符(1到无穷,不能是0次)

In [21]: re.findall('jb+','youbbbbbbblsdlajf')   #至少有一个b,0个匹配不上
Out[21]: []
In [22]: re.findall('jb+','youbbbbbbblsdlajbbbbbbbbbbf')
Out[22]: ['jbbbbbbbbbb']
In [24]: re.findall('j+f','youbjjjjjjflsdlajf')
Out[24]: ['jjjjjjf', 'jf']

  

?:指[0,1]闭区间的0到1,意思只能取前面一个元素的0次到1次

In [25]: re.findall('a?b','aaaabhghabfb')
Out[25]: ['ab', 'ab', 'b']  #aaaab的ab,hab只的ab,最的fb是匹配0个a 

 

{}: 定义匹配范围(至少n次)

In [30]: re.findall('a{5}b','ab')
Out[30]: []                           #0个不行

In [31]: re.findall('a{5}b','aaaab')
Out[31]: []                           #4个不行

In [32]: re.findall('a{5}b','aaaaab')
Out[32]: ['aaaaab']                   #5个可以

In [33]: re.findall('a{5}b','aaaaaab')
Out[33]: ['aaaaab']                   #6个可以,不包括第1个

范围{1,3}(至少n次,最多n+1次)

In [34]: re.findall('a{1,3}b','b')      #0次
Out[34]: []

In [35]: re.findall('a{1,3}b','ab')     #1次
Out[35]: ['ab']

In [36]: re.findall('a{1,3}b','aab')    #2次
Out[36]: ['aab']

In [37]: re.findall('a{1,3}b','aaab')   #3次
Out[37]: ['aaab']

In [38]: re.findall('a{1,3}b','aaaab')  #4次,先锚定b,是按最大次数匹配,贪婪匹配
Out[38]: ['aaab']

 

Summary:
(1)、*等于{0,正无穷}
(2)、+等于{1,正无穷}
(3)、?等于{0,1}

 

[]: 字符集:可以带内容代表范围
多选一:

In [61]: re.findall('a[c,d]x','ax')      #没有一个
Out[61]: []

In [62]: re.findall('a[c,d]x','acx')     #有一个c
Out[62]: ['acx']

In [63]: re.findall('a[c,d]x','adx')     #有一个d
Out[63]: ['adx']

In [64]: re.findall('a[c,d]x','acdx')    #有cd
Out[64]: []

In [65]: re.findall('a[c    ,d]x','acx')  #在字符后面可有空格
Out[65]: ['acx']

In [66]: re.findall('[a-z]','adx')       #所有的小写字母都匹配,每次只匹配一个
Out[66]: ['a', 'd', 'x']

In [6]: re.findall('a[b,c]d','abcd')    ##实际不用逗号区分 
Out[6]: []

In [7]: re.findall('a[bc]d','abcd')
Out[7]: []

In [8]: re.findall('a[b,c]d','a,d')
Out[8]: ['a,d']

  

取消元字符的特殊功能(例外\ ^ -)

In [68]: re.findall('[w,*]','adx')   #*是特殊的元字符,在这里只表示*
Out[68]: []

In [69]: re.findall('[w,*]','awdx')
Out[69]: ['w']

In [70]: re.findall('[w,*]','awdx*')  #*的显示
Out[70]: ['w', '*']

In [71]: re.findall('[w,.]','awdx.')
Out[71]: ['w', '.']

In [73]: re.findall('[a-z1-9A-Z]','awA14')   #匹配所有数字和字母
Out[73]: ['a', 'w', 'A', '1', '4']

In [74]: re.findall('[a-z1-9A-Z]','ay23BD')  #写法不一样,效果一样
Out[74]: ['a', 'y', '2', '3', 'B', 'D']
In [75]: re.findall('[a-z,1-9,A-Z]','ay23BD')
Out[75]: ['a', 'y', '2', '3', 'B', 'D']

  

[^ ]: 取反

In [2]: re.findall('[^t]','ijdkdkty')        #除了t
Out[2]: ['i', 'j', 'd', 'k', 'd', 'k', 'y']

In [3]: re.findall('[^5,3]','id3jdkdkty')
Out[3]: ['i', 'd', 'j', 'd', 'k', 'd', 'k', 't', 'y']

In [4]: re.findall('[^5,3]','id3jdkdk5ty') #非3或非5
Out[4]: ['i', 'd', 'j', 'd', 'k', 'd', 'k', 't', 'y']

  

\ : 反斜杠
反斜杠后面接元字符去除特殊功能
反斜杠后面接一部分普通字符实现特殊功能
与普通字符的结合:

\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 匹配一个特殊字符的边界

\d

In [5]: re.findall('\d{11}','dslfj201920930293029032039302')  #匹配11个数字
Out[5]: ['20192093029', '30290320393']           ##匹配完第1个11个数字放进列表,再匹配第2个11个数字 

\s

In [8]: re.findall('\slfj','dslfj')
Out[8]: []
In [9]: re.findall('\slfj','ds lfj')  ##空白
Out[9]: [' lfj']

\w

In [10]: re.findall('\wlfj','ds lfj')  #空白不行
Out[10]: []

In [11]: re.findall('\wlfj','dslfj')
Out[11]: ['slfj']

In [12]: re.findall('\w','dslfj')
Out[12]: ['d', 's', 'l', 'f', 'j']

\b

In [13]: re.findall('I','I am LINDA')
Out[13]: ['I', 'I']  #可能有时的需求是要取第一个I,I后面有一个空格,\b可以捕捉到,但是它不代表空白
In [14]: re.findall('I\b','I am LINDA')
Out[14]: []
In [15]: re.findall(r'I\b','I am LINDA')
Out[15]: ['I']
In [16]: re.findall(r'I\b','I am LI$NDA') #与任何各特殊字符的边界都可以捕捉,第二个I后是$
Out[16]: ['I', 'I']
In [19]: re.findall(r'\bI',' Iam LI$NDA') #可以在不同位置捕捉
Out[19]: ['I']

  

\:去除特殊功能

In [22]: re.search('a.','ajd').group()
Out[22]: 'aj'
In [23]: re.search('a\.','ajd').group()
AttributeError: 'NoneType' object has no attribute 'group'  #加了\就变成点,没有匹配成功,而search没有匹配成功不能调用group,因为没有对象
In [24]: re.search('a\.','a.jd').group()
Out[24]: 'a.'

  

消除\特殊功能

In [26]: re.findall("\\","ddd\de")
error: bad escape (end of pattern) at position 0   #报错
In [27]: re.findall("\\\\","ddd\de")
Out[27]: ['\\']
In [28]: re.findall(r"\\","ddd\de")  #使用r,或者使用4个斜杠,但是显示两个斜杠
Out[28]: ['\\']

分析:代码是在Python的解释器中进行解释的,现在在python解释器引用re模块来使用正则表达式,re里面封装了语法规范,re中的\是有特殊功能的,所以在re里要使用\\来匹配一个\,但是第一步是使用python解释器来解释的,在python里的\也是有特殊意义的,在re本来使用\\来解释,在python里还要每个\使用两个\\来解释,所以在python解释器时使用4个\\\\\来解释一个\
另一种做法是加个r,也就是告诉python这是原生的字符器,不需要转译,直接两个\\就可以



() |或

In [30]: re.search('(as)+','adfdkasas').group()  ##as作为一个整体来重复匹配
Out[30]: 'asas'
In [31]: re.search('(es)|4','es').group()
Out[31]: 'es'
In [40]: re.search('(es)|4','4es').group()
Out[40]: '4'

与findall()结合的效果
注:findall()方法与()一起使用时,是把()组里面的内容取出来的

In [10]: re.findall('www.(\w+).com','www.shoyou.com')
Out[10]: ['shoyou']

  

?:取消组的权限

In [11]: re.findall('www.(?:\w+).com','www.shoyou.com')
Out[11]: ['www.shoyou.com']

  

分组实例
描述:(?P<id>\d{3})一个括号代表一个整体分组,?P固定写法给组命名,<>存放组的名字,\d{3}就是匹配的内容,\d{3}是匹配3个数字,这3个数的名字是id,\w{3}三个字母的名字是name

      In [43]: re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo')
Out[43]: <_sre.SRE_Match object; span=(10, 17), match='123/ooo'>

In [44]: re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo').group()
Out[44]: '123/ooo'

In [45]: re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo').group('id')
Out[45]: '123'

In [46]: re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo').group('name')
Out[46]: 'ooo'

  

2.与正则结合的常用方法
search: 匹配到第一个就不往下匹配

In [20]: re.search('zk','ljdflszklskdjfzk')
Out[20]: <_sre.SRE_Match object; span=(6, 8), match='zk'>  #返回是一个对象
In [21]: re.search('zk','ljdflszklskdjfzk').group()  #通过group方法取得结果
Out[21]: 'zk'

  

match

In [4]: import re

In [5]: lin=re.match('you','lkjfldsjyouds')

In [6]: print(lin)
None

In [7]: lin=re.match('you','youlkjfldsjyouds')   ##从开始匹配

In [8]: print(lin)
<_sre.SRE_Match object; span=(0, 3), match='you'>

In [9]: lin=re.match('you','youlkjfldsjyouds').group()

In [10]: print(lin)
you

  

split

In [11]: re.split('y','aaylklj')
Out[11]: ['aa', 'lklj']

In [12]: re.split('[y,k]','aaylklj')  ##注:先使用y分成aa,lklj,再使用k把已经分开的分,aa,l,lj
Out[12]: ['aa', 'l', 'lj']

In [14]: re.split('[y,a]','auylklj') #有空,y先分成au,lklj,a在分在a前面空格和u
Out[14]: ['', 'u', 'lklj']

  

sub(): 与字符串的replace相似

In [15]: re.sub('t.m','jerry','alsdfkjtomsdlf')   #规则   替换成什么内容   替换前的内容  替换次数
Out[15]: 'alsdfkjjerrysdlf'

In [13]: re.sub('\d','great','reid3you4',1)   #查找数字,然后替换
Out[13]: 'reidgreatyou4'

In [14]: re.subn('\d','great','reid3you4')    #subn提醒替换次数
Out[14]: ('reidgreatyougreat', 2)

  

complie():
描述:有一种规则可能要引用多次
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象.第二个参数flag是匹配模式,取值可以使按位或运算'|‘表示同时生效,比如re. | re.M
可以把正则表达式编译成一个正则表达对象. 可以把那些经常使用的正则表达式编译成正则表达式对象,这样可以提高一定的效率
一般情况:匹配多次,写多次

In [17]: re.findall('\.com','sdfkljds.comslk')
Out[17]: ['.com']

In [18]: re.findall('\.com','sdfewfsdasdfds.comslk')
Out[18]: ['.com']

使用complie实现

In [22]: obj=re.compile('\.com')   #直接编译对象,只编译一次,这里的参数是规则

In [23]: obj.findall('sdfkljds.comslk')  #调用多次时会效率稍微高点
Out[23]: ['.com']

In [24]: obj.findall('seaeerws.comslk')
Out[24]: ['.com']

  

finditer: 返回迭代器

In [15]: re.finditer('\d','reid3you4')
Out[15]: <callable_iterator at 0x7fba9a1420f0>

In [16]: next(re.finditer('\d','reid3you4'))
Out[16]: <_sre.SRE_Match object; span=(4, 5), match='3'>

In [17]: next(re.finditer('\d','reid3you4')).group()
Out[17]: '3'

  

Summary:
a. findall() : 所有结果都返回一个列表
b. search(): 返回匹配到第一个对象(object),对象可以调用group()返回结果
c. match(): 只在字符串开始匹配,也返回匹配到第一个对(object),对象调用group返回结果

posted @ 2018-04-09 10:19  Reid21  阅读(256)  评论(0)    收藏  举报