python re模块

发布时间:2018-03-18 15:55:59编辑:admin阅读(5270)

    正则表达式(可以称为REs,regex,regex pattens)是一个小巧的,高度专业化的编程语言,它内嵌于python开发语言中,可通过re模块使用。正则表达式的pattern可以被编译成一系列的字节码,然后用C编写的引擎执行。


    常用正则表达式符号,基本上,包含了90%的场景。

    '.'默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
    '^'匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
    '$'匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
    '*'匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
    '+'匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
    '?'匹配前一个字符1次或0次
    '{m}'匹配前一个字符m次
    '{n,m}'匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
    '|'匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
    '(...)'分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
    '\A'只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
    '\Z'匹配字符结尾,同$
    '\d'匹配数字0-9
    '\D'匹配非数字
    '\w'匹配[A-Za-z0-9]
    '\W'匹配非[A-Za-z0-9]
    's'匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
    '(?P<name>...)'分组匹配

    最常用的匹配语法

    re.match 从头开始匹配
    re.search 匹配包含
    re.findall 把所有匹配到的字符放到以列表中的元素返回
    re.splita 以匹配到的字符当做列表分隔符
    re.sub      匹配字符并替换

    反斜杠的困扰
    与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

    举个列子:

    匹配以Chen开头的字符串

    import re
    result = re.match("^Chen","ChenLong")
    print(result)

    执行输出

    _sre.SRE_Match object; span=(0, 4), match='Chen'

    结果是一个匹配对象,请注意结尾的match='Chen' 表示匹配出了Chen

    如果没有匹配上,结果为None


    打印匹配结果,使用group()方法查看

    print(result.group())

    执行输出 Chen

    注意:如果没有匹配上,使用group()会报错。


    上面的正则匹配规写死了,比如^Chen 这种需求,用in方法就可以实现了。

    下面说一个简单的例子

    匹配以Chen开头的以及后面的数字

    import re
    result = re.match("^Chen\d","Chen356Long")
    print(result.group())

    执行输出

    Chen3


    注意:

    \d 表示匹配一个数字

    如果想要匹配多个数字,使用\d+

    import re
    result = re.match("^Chen\d+","Chen356Long")
    print(result.group())

    执行输出

    Chen356


    匹配任意字符.+

    res = re.match(".+","Chen321Long123")
    print(res.group())

    执行输出

    Chen321Long123


    匹配单个字符.

    res = re.match(".","Chen321Long123")
    print(res.group())

    执行输出: C


    匹配Long

    res = re.match("^L.+g","Chen321Long123")
    print(res)

    执行输出: None

    为什么呢?因为match是从左至右匹配,由于Long在字符串的中间,写任何正则都无法匹配出Long。

    需要用到另外一个方法search,表示从整个文本中去搜索。结果只会返回一次,如果有多个结果,会返回第一个结果。

    res = re.search("L.+g","Chen321Long123")
    print(res.group())

    执行输出: Long


    如果使用L.+g$ 是匹配不到Long的,为什么呢?

    $表示匹配整个字符串的结尾,而结尾是3。由于123不是我想要的,所以不能写g$


    由于.+是匹配任意字符,如果只想匹配字母呢?使用[a-z]

    res = re.search("L[a-z]+g","Chen321Long123")

    匹配所有字母大小写呢?使用[a-zA-Z]

    res = re.search("L[a-zA-Z]+g","Chen321Long123")


    匹配jack

    res = re.search("[a-z]+k","123#tom#jack#rose")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(8, 12), match='jack'


    '?' 匹配前一个字符1次或0次

    匹配字母a

    res = re.search("a?","alin")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 1), match='a'


    匹配字母a

    res = re.search("a?","lina")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 0), match=''

    结果显示没有匹配上,请注意,? 可以匹配0次,也就是不匹配的情况。所以它的结果不是None


    '?' 匹配前一个字符1次或0次


    匹配aa或者aaa

    res = re.search("aaa?","aalinaaa")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 2), match='aa'


    请注意aaa? 需要拆分一下aa和aaa? 为什么呢? '?'是匹配0次或者1次数

    aaa?匹配0次就是aa,匹配1次,就是aaa?


    '{m}' 匹配前一个字符m次

    匹配3个数字

    res = re.search("[0-9]{3}","aa1x2a345aa")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(6, 9), match='345'


    匹配1到3次

    res = re.search("[0-9]{1,3}","aa1x2a345aa")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(2, 3), match='1'


    匹配所有数字

    res = re.search("[0-9]+","aa1x2a345aa")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(2, 3), match='1'


    为什么只有一个1呢?因为search只会返回一个结果,后续的不再返回。这个时候,需要用到findall方法

    注意:findall没有group()方法

    res = re.findall("[0-9]+","aa1x2a345aa")
    print(res)

    执行输出:

    ['1', '2', '345']


    所有的数字,都匹配出来了。


    只匹配第3次的结果

    res = re.findall("[0-9]{3}","aa1x2a345aa")
    print(res)

    执行输出:

    ['345']


    '|' 匹配|左或|右的字符


    匹配abc或者ABC

    res = re.findall("abc|ABC","ABCBabcCD")
    print(res)

    执行输出:

    ['ABC', 'abc']


    '(...)'分组匹配


    匹配abc,在匹配c 2次

    res = re.search("abc{2}","xiabccc")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(2, 6), match='abcc'


    复杂的例子

    匹配abc 2次,匹配||= 2次。注意:\| 转义了,表示|

    res = re.search("(abc){2}(\|\|=){2}","abcabc||=||=")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 12), match='abcabc||=||='


    '\A'只从字符开头匹配

    '\Z'匹配字符结尾,同$


    '\A' 效果和'^' 是一样的。


    匹配以数字开头,字母结尾

    res = re.search("\A[0-9]+[a-z]\Z","123a")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 4), match='123a'


    '\d' 匹配数字

    res = re.search("\A\d+[a-z]\Z","123a")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 4), match='123a'


    '\D' 匹配非数字

    匹配非数字

    res = re.search("\D+","123a$ -\n")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(3, 8), match='a$ -\n'


    '\w'匹配[A-Za-z0-9]

    res = re.search("\w+","1dF23$- \r\na")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 5), match='1dF23'


    '\W'匹配非[A-Za-z0-9]

    res = re.search("\W+","1dF23$- \r\na")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(5, 10), match='$- \r\n'


    's'匹配空白字符、\t、\n、\r

    res = re.search("\s+","1dF23$- \r\na")
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(7, 10), match=' \r\n'


    '(?P<name>...)' 分组匹配 


    组名为id,匹配数字

    res = re.search("(?P<id>[0-9]+)","abcd1234daf@34")
    #使用groupdict()方法打印组名
    print(res.groupdict())

    执行输出:

    {'id': '1234'}


    再添加一个分组name,匹配字母大小写

    res = re.search("(?P<id>[0-9]+)(?P<name>[a-zA-Z]+)","abcd1234daf@34")
    print(res.groupdict())

    执行输出:

    {'name': 'daf', 'id': '1234'}

    返回的结果是一个字典,如果想取值的话,使用如下方法:

    res = re.search("(?P<id>[0-9]+)(?P<name>[a-zA-Z]+)","abcd1234daf@34")
    print(res.groupdict())
    #第一种方法,直接传值
    print(res.group("id"))
    #第二种方法,用字典的方式
    print(res.groupdict()['name'])

    执行输出:

    {'id': '1234', 'name': 'daf'}

    1234

    daf


    举个复杂的例子

    身份证号,前2位是省,再后面2位是市,再后面2位是区,再后面8位是出生日期

    res = re.search("(?P<province>[0-9]{2})(?P<city>[0-9]{2})(?P<area>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city")
    print(res)

    执行输出:

    {'birthday': '1993', 'city': '14', 'province': '37', 'area': '81'}


    re.split 以匹配到的字符当做列表分隔符


    res = re.split("[0-9]","abc12de3f45GH")
    print(res)

    执行输出:

    ['abc', 'de', 'f', 'GH']


    re.sub   匹配字符并替换

    res = re.sub("[0-9]+","|","abc12de3f45GH")
    print(res)

    执行输出:

    abc|de|f|GH


    只替换一个

    res = re.sub("[0-9]+","|","abc12de3f45GH",count=1)
    print(res)

    执行输出:

    abc|de3f45GH


    仅需轻轻知道的几个匹配模式

    re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
    M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上面)
    S(DOTALL): 点任意匹配模式,改变'.'的行为


    忽略大小写

    res = re.search("[a-z]+","abcA",flags=re.I)
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 4), match='abcA'


    res = re.search(r"^a","\nabc\neee",flags=re.M)
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(1, 2), match='a'


    匹配任意字符

    res = re.search(r".+","\nabc\neee",flags=re.S)
    print(res)

    执行输出:

    _sre.SRE_Match object; span=(0, 8), match='\nabc\neee'



关键字

上一篇: python hashlib模块

下一篇: python 面向对象