继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Python 正则表达式

慕虎7371278
关注TA
已关注
手记 1259
粉丝 203
获赞 873

正则语法

对匹配类型

(1).:代表除换行外任意一个字符(除了换行符,但是如果开了编译标志DOTALL后就可以包括换行符了),举例:(search等正则相关方法具体用法参考后面)

>>> re.search(r's.a','where is abc in')
<_sre.SRE_Match object; span=(7, 10), match='s a'>

所以这里.对应了一个空格,如果就要匹配.这个字符的话可以前面加\防止被转义,举例:\.,此时就是.
(2)\d:代表任意一个数字,例如查找一个ip地址:

>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d','192.168.134.253')
<_sre.SRE_Match object; span=(0, 15), match='192.168.134.253'>

(3)\w:匹配字母、数字或下划线或汉字
(4)\s:匹配任意的空白符
(5)(匹配的字符)\1:就是要匹配的字符并且把括号里的内容匹配两次,举例:

>>> re.search(r'a(bc)\1','abcabcbc')
<_sre.SRE_Match object; span=(3, 8), match='abcbc'>

(因为括号里的是bc,所以就把bc匹配了两次),也可以用r'a(bc){2}'替代,效果相同
(6)\ASCII值:对应ASCII表内容,例如八进制的60对应ASCII的0,则:

>>> re.search(r'abc\060','abcabc0')
<_sre.SRE_Match object; span=(3, 7), match='abc0'>

(7)^:匹配字符串的开始,也就是只有这个字符串在开始位置才可以查到(\A默认情况下跟其一样),举例:

>>> re.search(r'^abc','abcde')
<_sre.SRE_Match object; span=(0, 3), match='abc'>>>> re.search(r'^abc','fabcde')    #没有结果,即None(因为abc不为开始符号)

(8)$:匹配字符串的结束,和上面的相反(\Z默认情况下跟其一样),举例:

>>> re.search(r'abc$','abscdeabc')
<_sre.SRE_Match object; span=(6, 9), match='abc'>

(9)\b:匹配单词的边界,除了字母、_和数字以外都是边界(即\b可以替代这三种类型),举例:

>>> re.findall(r'\babc\b','abc.abc!abc3() abc_bbc')
['abc', 'abc']

只有前两个abc被找出,但是第三个后面有数字,第四个有下划线,所以abc3,abc_bbc都被看作一个单词——其实只要符合变量标准的都被看作一个单词,即字母数字下划线连在一起的
(10)\B:匹配非单词的边界,和上面那个相反,使用时只在非单词尾加,举例:

>>> re.findall(r'abc\B','abc.abc!abc3() abc_bbc')
['abc', 'abc']  #只有后两个被找出,因为前两个是单词

(11)\w:匹配所有字类字符和下划线,像空格、标点符号啥的不匹配,举例:

>>> re.findall(r'\w','abc.a!!你好_-お')
['a', 'b', 'c', 'a', '你', '好', '_', 'お']  #可以发现像!、.、-这些都没了

(12)\W:和上面的相反,举例:

>>> re.findall(r'\W','abc.a!!你好_-お')
['.', '!', '!', '-']
对匹配范围

(1)[存在的字符或者范围]:查找对应[]的一个字符
(2)[含有的字符]:可以放几个字符,但记住大小写敏感,举例:

>>> re.findall(r'[Wabcde]','www.baidu.com')
['b', 'a', 'd', 'c']  #W不匹配w

因为[]里面的字符都是看作普通字符看待,所以[.]也只是匹配.,而不是任意字符,比如:

>>> re.findall(r'[Wabcde.]','www.baidu.com!@#')
['.', 'b', 'a', 'd', '.', 'c']    #结果并没有匹配!、@、#

(3)[字符1-字符2]:左边的ASCII要比右边的小,可以匹配字符范围,举例1:

>>> re.findall(r'[a-z]','www.baidu.com')
['w', 'w', 'w', 'b', 'a', 'i', 'd', 'u', 'c', 'o', 'm']

因为里面字符是按ASCII码表排序的,所以比如a的A大,所以[A-a]可以,但[a-A]不可以,举例2:

>>> re.findall(r'[A-a]','www.baidu.com')
['a']>>> re.findall(r'[a-A]','www.baidu.com')
sre_constants.error: bad character range a-A at position 1  #报错

但因为匹配的是一个字符,所以数字的范围只有[0-9],一堆数字只会看作一个一个通配符,举例:

>>> re.findall(r'[0-3856]','ww32w.baidu.com')
['3', '2']  #匹配0到3还有8/5/6中的一个数,而不是匹配0到3856的数

(4)[^不含有的字符]:可以匹配不含有的字符,举例:

>>> re.findall(r'[^a-z.]','www.baidu.com!@#')
['!', '@', '#']  #不含所有小写字母和.

注:
^得放在第一个才有效果,否则只是单纯的匹配^这个符号

对匹配长度

(1)匹配字符{匹配长度}:可以匹配字符的长度,{}前的一个字符是我们要匹配的字符,{}里可以是一个数字,代表有几个,也可以是两个数字(用逗号隔开),代表长度可取的范围({1,5}代表至少1个最多5个,{1,}代表最少1个),比如前面ip地址我们就能更精准的匹配了:

>>> re.findall(r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}','192.168.134.253')
['192.168.134.253']

但如果要更精准,要匹配0-255的数就可以:

for each in range(257):
    q = re.findall(r'[1]\d{2}|2[0-4]\d|25[0-5]|\d{1,2}',str(each))    print(each,'-->',q)
部分结果:
0 --> ['0']
1 --> ['1']
2 --> ['2']
...
255 --> ['255']
256 --> ['25', '6']#可以发现只有0-255匹配成功#匹配法则:#1开头时,个位和十位数值随意#2开头,十位在0-4的个位随意,25开头的个位只能是0-5#还有两位数和一位数的#把以上几种或起来

此时更精准的ip匹配就可以是:

>>> q = re.search(r'(([1]\d{2}|2[0-4]\d|25[0-5]|\d{1,2})\.){3}([1]\d{2}|2[0-4]\d|25[0-5]|\d{1,2})','192.168.1.1')>>> q.group()'192.168.1.1'#0-255加.重复3次,最后面再来个0-255但不加.#其中每个0-255用()括起来,前面重复3次的内容也用括号括起来,不然只会把.重复3次

(2)匹配字符*:匹配前面的字符0次或多次,相当于{0,},举例:

>>> re.findall(r'abc*','asfabccd')
['abcc']#此时c有2个所以都被匹配

(3)匹配字符+:匹配前面的字符1次或多次,相当于{1,}
(4)匹配字符?:匹配前面的字符0次或1次,相当于{0,1}
注:
(2)和(3)的匹配方法有种贪婪的特性,有时可能会把字符匹配多了,比如字符串str1 = '<html></html>',我们只要匹配<html>,所以可能用:re.search('<.+>',str1)(以<开头,后面一个或多个任意字符,最后以>结尾),结果匹配的是:'<html></html>',说明匹配东西多了(因为此时他会尽可能多的匹配,所以不会从左到右直到碰到第一个>就结束,其相当于从最右面开始找第一个>然后结束),所以为了避免这种情况,就会用到?(此时?不代表0或1次,而是代表非贪婪模式),即:re.search('<.+?>',str1),这样就会从左到右当遇到第一个>时结束,所以此时结果就是'<html>'

常用方法

import re
虽然像find()也能起到查找字符的功能,但re模块下的函数(比如search)可以使用正则表达式,具体如下:
1.search('要查找的字符', '从哪里查找')
结果返回这个查的字符在查找的哪些位置,举例:

>>> re.search(r'abc','where is abc in')    #开头加`r`防止字符串转义等问题<_sre.SRE_Match object; span=(9, 12), match='abc'>#第一个分号前不用管,span代表位置,match代表匹配的字符,没有就返回none

注:
(1)如果要只获得查找到的字符结果可以用group()函数,举例:

>>> p = re.search(' (\w+) (\w+)','may i help you')#匹配第一位为空格,第二位是一直到非空格、符号位,接着空格,然后再一直到非空格、符号位的字符串>>> p.group()' i help'

group()如果捕获的里面有子组,还可以分开看子组内容,例如对上面的:

>>> p.group(1)'i'>>> p.group(2)'help'

(2)如果要获得span里的参数,也就是匹配的是第几位到第几位,就可以用span,如果只要知道开头或结尾位置,那么可以用startend,一个代表从第几位开始匹配,一个是第几位结束匹配,例如还是对上面的p:

>>> p.span()
(3, 10)>>> p.start()3>>> p.end()10

注2
内置函数find()也可以实现,会返回起始位置,举例:

>>> 'where is abc in'.find('abc')9

2.findall('要匹配的字符', '从哪里查找')
结果以一个列表形式返回所有匹配上的字符(都是单个字符),举例:

>>> re.findall('a.c','abc,acc,a5c')
['abc', 'acc', 'a5c']

并且该函数有个十分智能的方法,就是可以只返回一个我们想要的内容序列,比如上面返回的都是a开始,c结束,中间一个任意字符的数组,现在我们只要中间的那个字符,就可以在我们想要的那个字符上加上括号,例如:re.findall('a(.)c','abc,acc,a5c'),此时结果就是我们想要的['b', 'c', '5']了(当然这是在返回的字符串有子组的前提下)
注:
因为有子组前提下有括号的地方都会被单独弄出来,假如要弄一个ip地址:

>>> re.findall(r'(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])','192.31.123.112')
[('123.', '123', '112')]

结果并不是我们想要的效果,其实是他自认为括号的3个地方是我们想要的,所以就把这3个地方分开组成一个元组给我们,为了避免这种情况发生,我们应该在不想被智能读取的括号开头加上个?:,还是刚才那个举例:

>>> re.findall(r'(?:(?:[01]?\d?\d|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d?\d|2[0-4]\d|25[0-5])','192.31.123.112')
['192.31.123.112']

3.compile('正则表达式')
这个是编译正则表达式的函数,可以提前把正则表达式存到一个类中,当需要重复使用某一个表达式规则时,使用这函数就比较方便,举例:

p = re.compile('[a-z]')     #此时把该表达式存到p里,p变成存放该表达式的类p.findall('www.BaiDu.com')  #不用再从re模块调用,直接调用p就可以使用该表达式规则结果为:
['w', 'w', 'w', 'a', 'i', 'u', 'c', 'o', 'm']#匹配所有小写字母

4.sub('正则表达式', '替换成的内容', '字符串')
可以把符合正则的字符都替换成其他字符,举例:

>>> a = re.compile('\(.+?\)')>>> b = 'abc(fg)de'>>> re.sub(a, '\t', b)  #把所有括号连同其包起来的内容去掉'abc\tde'

5.编译标志
(使用方法:re.compile('正则表达式','re.编译标志')
(1)DOTALL
此时.可以匹配包括换行符的任何符号(也就是所有符号),举例:

q = re.compile(r'a.b',re.DOTALL)
q.findall('a\nb,a b')
结果为:
['a\nb', 'a b']#可以发现'\n'现在也能匹配了

(2)IGNORECASE:此时匹配时大小写不区分
(3)VERBOSE:启用详细的正则表达式,此时空格会被忽略,同一行的#后面是注释(当然如果还想空格就\,想#就\#),举例:

q = re.compile(r"""
    (
    0[0-7]+ #八进制
    |[0-9]+ #十进制
    |x[0-9a-fA-F]+  #十六进制
    )
    ;   #结尾分号
    """, re.VERBOSE)

如上所示,一个正则表达式的编译就美观多了

6.re.S

允许在多行内匹配,相当于匹配时加上\n
举例:

>>> x = """abc
    de
    fgh
""">>> re.findall('a(.*?)h', x)
[]>>> re.findall('a(.*?)h', x, re.S)
['bc\n\tde\n\tfg']

可以看出原来无法匹配到换行的部分,但是加上re.S以后,就可以匹配上了



作者:dawsonenjoy
链接:https://www.jianshu.com/p/787c8e4a3652


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP