• Python正则表达式-1


    本文基于Python官方手册进行翻译和整理,包括对正则表达式的简介、Python正则库API、以及一些使用样例。

    参考手册:
    http://docs.python.org/2/library/re.html?highlight=re#re
    http://docs.python.org/2/howto/regex.html#regex-howto

    http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html

    http://download.csdn.net/detail/gzhouc/8891155

    简介

    Python中主要使用re模块进行正则表达式匹配,re使用perl风格的语法,并对8字节ASCII码以及Unicode编码都提供了良好的支持。

    在常规字符串中使用正则表达式是一件比较麻烦的事,拿匹配字符来说,因为是正则表达式中的特殊字符,对其匹配需要使用\,而’’又是字符串的转义字符,所以需要用\\来匹配一个。是不是很麻烦?这样写出来的正则表达式又长又难懂,好在Python为我们提供了原始字符串————在字符串前加r,原始字符串中的字符不会被转义,可以说是所见即所得,比如r" "就表示了字符串” ”而不是回车。因此,大多数Python程序员基本都只用原始字符串来表示模式串。

    正则表达式关键字

    正则表达式关键字是指用来进行匹配的字符,这些字符可以匹配特定的文本串。需要注意的是,如果要使这些字符表达原意,要用进行转义。此外,需要转义的还包括一些分隔符,如(|等。

    这些关键字如下

    基本关键字
    .           常规模式匹配除了"
    "外的所有字符,DOTALL模式下"
    "也会被匹配
    ^           匹配字符串的开头,MULTILINE模式下会匹配每行开头
    $           匹配字符串的即为,MULTILINE模式下会匹配行尾
    *           匹配*号前面的内容0次至无限次
               转义符,在匹配字符*号等特殊字符时使用
    |           或,A|B表示只要A和B中任意匹配一个
    []          匹配方括号内字符集中的任一字符,注意里面的特殊字符会失去特殊意义,以及^和-要进行转义
    
    量词
    +           匹配+号前内容1次至无限次
    ?           匹配?号前内容0次到1次
    {m}         匹配前面的内容m次
    {m,n}       匹配前面的内容m到n次
    *?,+?,??,{m,n}?    前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
    
    分组匹配
    (..)        分组,首先是会在group函数中得到这个分组,其次是会成为基本重复单位(+,?,*等)
    (?..)       ()的扩展形式,()中的内容不会被作为分组记录(?P<name>除外),扩展有以下几种
    (?:..)      最基础的扩展,()内的内容不会被作为分组记录
    (?P<name>)  该分组会被作为分组记录,并且分组名为name
    (?P=name)   后向引用(?P<name>)中的内容
    (?#...)     注释,括号中的内容会被忽略
    (?=...)     之后的字符串需要匹配括号中的内容,但不消耗字符串,比如a(?=b)只能匹配ab,接下来从b开始继续匹配
    (?!...)     之后的内容不能匹配括号中的内容,但不消耗字符串
    (?<=...)    之前的字符串需要匹配括号中的内容,但不消耗字符串
    (?<!...)    之前的内容不能匹配括号中的内容,但不消耗字符串
    (?(id/name)yes-pattern|no-pattern)  如果指定的id或name的分组匹配到内容,则使用yes-pattern匹配,否则使用no-pattern
    (?iLmsux)   用于改变字符串的匹配模式(后面会说),只能用在开头,也可以在compile时使用flag参数来指定匹配模式
    
    ""匹配
    
    umber     后向引用
    umber中匹配的内容
    使用
    A          匹配字符串开头
              匹配字符串结尾
    w          匹配[a-zA-Z0-9_]
    W          匹配[^w]
              匹配[^w]和[w]之间的字符,也就是匹配字符串边界
    B          匹配[^]
    d          匹配[0-9]
    D          匹配[^d]
    s          匹配[ 	
    
    fv],即所有空白字符
    S          匹配[^s]
    另外有一些常规转义符,包括a  f 
     
     	 v x \,注意这里匹配backspace时,必须在[]中使用
    

    Python正则库API

    选项

    re库API中,一般都有flags参数,通过该参数指定正则表达式选项。传递时一般使用简写,比如开启DOTALL和MULTILINE使用re.I|re.M

    A  ASCII       使wWBdD匹配ASCII字符
    I  IGNORECASE  忽略大小写
    L  LOCALE      使wWB匹配本地字符集
    M  MULTILINE   多行模式,"^" 匹配每行开头,"$"匹配每行结尾
    S  DOTALL      "." 匹配所有字符,包括"
    "
    X  VERBOSE     详细模式,忽略空白可以加入注释
    U  UNICODE     使wWBdD匹配unicode字符集
    

    API速查

    这里只是列出API,便于查阅,后面会详细介绍API的使用。建议先跳过这一段,直接看后面的Sample,再回过头来看这一段。

    API分为三组,第一组是模块API(Module Contents),通过re.xx()使用;第二组是表达式API(Regular Expression Objects),re.complie()函数会返回一个表达式对象,通过该对象使用的函数;第三组是匹配对象API(Match Objects),像search这些函数都会返回一个匹配结果,这组API用于操作结果集。

    re库对于很多函数,例如match,都提供了两种调用方式,一是直接通过re库调用,将正则表达式作为参数,二是先用complie编译表达式,通过返回的对象调用,方法二在正则表达式会被多次使用时会减少重复编译花费的时间。

    模块APII(Module Contents)
    re.compile(pattern, flags=0)                预编译一个正则表达式,返回一个表达式对象(Regular Expression Objects)
    re.search(pattern, string, flags = 0)       在字符串中找匹配的串,返回第一个匹配到的匹配对象
    re.match(pattern, string, flags=0)          从头开始匹配,返回匹配对象
    re.split(pattern, string, maxsplit=0, flags=0)  使用pattern分割字符串,返回一个结果list
    re.findall(pattern, string, flags=0)        search加强版,返回所有的匹配对象的list
    re.finditer(pattern, string, flags=0)       返回一个迭代器,用户可以使用迭代器查看所有匹配对象
    re.sub(pattern, repl, string, count=0, flags=0)  使用repl替换string中pattern匹配到的部分;
                                                     这里repl可以是一个函数,参数是匹配对象,返回要替代的串
    re.subn(pattern, repl, string, count=0, flags=0) 类似sub,返回元组(new_string, number_of_subs_made)
    re.escape(string)                           将所有的非字母数字字符前加""后返回
    re.purge()                                  清空正则表达式缓存
    
    表达式API(Regular Expression Objects)
    flags                                       编译时的flag
    groups                                      表达式中分组的数量
    groupindex                                  以有别名的组别名为键、编号为值的字典
    pattern                                     编译时用的表达式字符串
    search(string[, pos[, endpos]])             从Pos处开始查找字符串,返回匹配对象
    match(string[, pos[, endpos]])              从Pos处匹配字符串,返回匹配对象
    split(string, maxsplit=0)                   同re.split
    findall(string[, pos[, endpos]])            从Pos处查找所有匹配的字符串,返回所有匹配对象的list
    finditer(string[, pos[, endpos]])           从Pos处查找所有的字符串,返回一个迭代器
    sub(repl, string, count=0)                  同re.sub
    subn(repl, string, count=0)                 同re.subn
    
    匹配对象API(Match Objects)
    pos                     传递给函数的pos
    endpos                  传递给函数的endpos
    lastindex               最后一个捕获的group的下标
    lastgroup               最后一个捕获的group的名字
    re                      调用match或者search的表达式对象
    string                  match或者search的字符串
    expand(template)        将匹配到的分组代入template中然后返回。template中可以使用id或g<id>、g<name>引用分组
                            注意0不能使用,另外10将被认为是第10个分组,如果你想表达1之后是字符'0',只能使用g<1>0。
    group([group1, ...])    获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回,0代表整个匹配串
    groups([default])       以元组形式返回全部分组截获的字符串,相当于调用group((1,2,…n))
    groupdict([default])    返回以有别名的组的别名为键、以该组截获的子串为值的字典
    start([group])          返回指定组的串在原串中的起始索引
    end([group])            返回指定组的串在原串中的结束索引
    span([group])           返回(start(group), end(group))
    

    使用re模块

    在整个re库中用到的对象一共有三个,分别是顶级的re对象、re.compile函数返回的Pattern对象、match、serach等函数返回的Match对象。而使用re库的方法也有两种,一种是直接使用re对象的方法,一种是先complie表达式返回Pattern对象,再使用Pattern对象来操作,这两者的区别是后者可以减少重复编译的时间。实际上即使不使用compile,re库也会缓存一些近期使用过的正则表达式编译结果,所以这里不用太担心两者的效率差别。

    compile
    作用就是编译一个表达式,以下两段代码作用相同

    # use compile
    p = re.compile(r'ab*')
    r = p.match('abcc')
    print r.group(0)
    
    # don't use compile
    r = re.match(r'ab*', 'abcc')
    print r.group(0)
    
    # output
    ab
    ab
    

    匹配对象(Match Object)
    所谓匹配对象,就是match,search,findall等搜索操作返回的结果对象,下面举个简单的例子看下匹配对象(Match Object)中各种方法的使用
    我们使用正则表达式([a-z]+) (?P<digit>[d]+)来匹配类似于abc 123这样的串。我们捕捉字符串组和数字组,并给数字组命名为digit。

    p = re.compile(r'([a-z]+) (?P<digit>[d]+)')
    r = p.search('name su, id 123')
    print 're        :', r.re               #re object used
    print 'string    :', r.string           #string
    print 'pos       :', r.pos              #search start pos
    print 'endpos    :', r.endpos           #search end pos
    print 'lastindex :', r.lastindex        #last group index
    print 'lastgroup :', r.lastgroup        #last group name
    print 'groups    :', r.groups()         #all group from index 1
    print 'group     :', r.group(0, 1, 2)   #group index 0, 1, 2
    print 'groupdict :', r.groupdict()      #group name dict
    print 'start     :', r.start(2)         #start pos of group 2
    print 'end       :', r.end("digit")     #end pos of group digit
    print 'span(num) :', r.span(2)          #range of group 2
    print 'span(name):', r.span("digit")    #range of group digit
    print 'expand    :', r.expand(r'g<digit> 1') #swap group 1 with 2
    
    # output
    re        : <_sre.SRE_Pattern object at 0x015AE860>
    string    : name su, id 123
    pos       : 0
    endpos    : 15
    lastindex : 2
    lastgroup : digit
    groups    : ('id', '123')
    group     : ('id 123', 'id', '123')
    groupdict : {'digit': '123'}
    start     : 12
    end       : 15
    span(num) : (12, 15)
    span(name): (12, 15)
    expand    : 123 id
    

    可以看到,对于有名组,我们不仅可以用Index来引用该组,还可以使用组名来引用,这在分组较多时会十分有用。在expand函数中使用了后向引用,1表示group 1,g<digit>表示group digit

    search VS match
    search和match的作用是相近的,都是在字符串中匹配一个模式串,唯一的不同是match从首字符开始搜索,而search不要求。search在正则前加^可以达到和match相同的作用。
    依然用前面的正则表达式,结果如下。

    r = re.search(r'([a-z]+) (?P<digit>[d]+)', 'name id 123')
    print r
    r = re.match(r'([a-z]+) (?P<digit>[d]+)', 'name id 123')
    print r
    r = re.search(r'^([a-z]+) (?P<digit>[d]+)', 'name id 123')
    print r
    
    # output
    <_sre.SRE_Match object at 0x016954A0>
    None
    None
    

    sub
    sub用于替换匹配到的内容,它的特色是替换参数可以是一个函数,我们看一下如何使用函数来进行替换。
    这个例子是将所有的数字从十进制转换成十六进制数。

    p = re.compile(r'[d]+')
    def hexrepl(match):
        value = int(match.group())
        return hex(value)
    print p.sub(hexrepl, 'id 123, age 20.')
    
    # output
    id 0x7b, age 0x14.
    

    这里也可以用lambda表达式使程序更加简洁

    p = re.compile(r'[d]+')
    print p.sub(lambda x: hex(int(x.group())), 'id 123, age 20.')
    
    # output
    id 0x7b, age 0x14.
    

    split
    它是字符串split函数的强化版,可以使用正则表达式
    一个简单的例子,分离字符串中的数字。注意如果使用了捕获括号,捕获的内容也会出现在结果中。

    print re.split(r'D+', '123asd12 41 a12')
    print re.split(r'(D+)', '123asd12 41 a12')
    
    # output
    ['123', '12', '41', '12']
    ['123', 'asd', '12', ' ', '41', ' a', '12']
    

    findall && finditer
    search的加强版,findall返回所有结果,finditer返回一个迭代器,延用上面的例子。

    p = re.compile(r'[d]+')
    r = p.findall('id 123, age 20.')
    print r
    r = p.finditer('id 123, age 20')
    print [s.group(0) for s in r]
    
    #out put
    ['123', '20']
    ['123', '20']
    

    More

    关于Python中的正则表达式,基本就是这些内容了。能写出一个性能良好并且正确的正则表达式,也是对一个程序员的基本要求了,本文并没有详细介绍如何使用正则表达式,如果想用好正则表达式,还要进一步学习有关正则表达式的高级知识。

  • 相关阅读:
    python异常触发及自定义异常类
    python for i in range(x)应用的问题
    季羡林 暮年沉思录
    再谈python的list类型参数及复制
    Python 列表推导式
    JavaScript:垃圾数据是如何自动回收的?
    JavaScript:this的用法
    JavaScript:浅谈闭包及其回收原则
    ES6:async / await ---使用同步方式写异步代码
    五大主流浏览器与四大浏览器内核
  • 原文地址:https://www.cnblogs.com/double12gzh/p/10166239.html
Copyright © 2020-2023  润新知