zoukankan      html  css  js  c++  java
  • Regular Expression:Python遇见正则表达式

    正则表达式的基本概念

      正则表达式为高级的文本模式匹配、抽取或文本形式的搜索和替换功能提供了基础。
      简单地说,正则表达式(Regular Expression,简称为 regex)是一些由字符和特殊符号组成的字符串,它们描述了模式的重复或者表述多个字符,于是正则表达式能按照某种模式匹配一系列有相似特征的字符串。换句话说, 它们能够匹配多个字符串……
      术语“匹配”(matching),指的是术语“模式匹配”(pattern-matching)。在Python语言的术语中,主要有两种方法完成模式匹配:“搜索”(searching)和“匹配”(matching)。搜索即在字符串任意部分中搜索匹配的模式;而匹配是指判断一个字符串能否从起始处全部或者部分地匹配某个模式。搜索通过search()函数或方法来实现,而匹配通过调用match()函数或方法实现。总之,当涉及模式时,全部使用术语“匹配”。

    第一部分供快速查阅,正则表达式在Python中的用法在第二部分介绍。

    老司机专属通道

    1. 元字符^$*+?.|(){}[]
    • 正则表达式由两种基本字符类型组成:原义文本字符和元字符
    • 元字符是正则表达式中有特殊含义的非字母字符,这里的特殊含义要根据上下文语义来判断,含义并不唯一。
    1. 量词?+*{n}{n,m}{n,}
    2. 字符类
    • 使用元字符[]来构建一个简单的类。
    • 字符类取反——^
    • 范围类,如[0-9a-b]
    1. 预定义类及其等价类
    字符 等价类
    . [^ ]
    d [0-9]
    D [^0-9]
    s [ fv]
    S [^ fv]
    w [a-zA-Z0-9_]
    W [^a-zA-Z0-9_]
    1. 边界^$B
    • ^$分别代表串开始和串结束
    • B分别代表单词边界和费单词边界
    1. 分组与或()|


    为什么要使用正则表达式

    先来看几个使用字符串方法的例子:

    # 字符串匹配就能实现
    # 场景1. 找到course开头的语句
    def find_start_str(file_name, start_str):
        file = open(file_name)
    
        for line in file:
            if line.startswith(start_str):
                print(line)
    
        file.close()
    
    find_start_str('course.txt', 'course')
    
    
    # 场景2, 找到course开头和2019结尾的语句
    def find_start_end_str(file_name, start_str, end_str):
        file = open(file_name)
    
        for line in file:
            if line.startswith(start_str)
                    and line[:-1].endswith(end_str):  # Python是以
    结束的
                print(line)
    
        file.close()
    
    find_start_end_str('course.txt', 'course', '2019')
    
    
    # 场景3,匹配一个下划线或者字母开头的变量名
    a = "_valuel"
    print(a and(a[0] == '_' or 'a' <= a[0] <= 'Z'))
    

    course.txt文件:

    course Java 2019
    course Html 2018
    course Python 2010
    course C++ 2018
    course Python3 2019
    
    C 0000
    C# 0000
    .net 0000
    php 0000
    

    问题:每一次匹配都要单独写函数完成,有没有相应简单的方法?

    Python正则表达式re模块

    1. re.Match

    Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。

    属性:

    • endpos:The index into the string beyond which the RE engine will not go.文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
    • lastgroup:The name of the last matched capturing group.最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
    • lastindex:The integer index of the last matched capturing group.最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
    • pos:The index into the string at which the RE engine started looking for a match.文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
    • re:The regular expression object.匹配时使用的Pattern对象。
    • regs
    • string:The string passed to match() or search().匹配时使用的文本。

    方法:

    • end(self, group=0, /)
      Return index of the end of the substring matched by group.
      返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
    • expand(self, /, template)
      Return the string obtained by doing backslash substitution on the string template, as done by the sub() method.
      将匹配到的分组代入template中然后返回。template中可以使用id或g、g引用分组,但不能使用编号0。id与g是等价的;但10将被认为是第10个分组,如果你想表达1之后是字符’0’,只能使用g<1>0。
    • group(...)
      group([group1, …]) -> str or tuple.
      Return subgroup(s) of the match by indices or names.
      For 0 returns the entire match.
      获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
    • groupdict(self, /, default=None)
      Return a dictionary containing all the named subgroups of the match, keyed by the subgroup name.
      default
      Is used for groups that did not participate in the match.
      返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。
    • groups(self, /, default=None)
      Return a tuple containing all the subgroups of the match, from 1.
      default
      Is used for groups that did not participate in the match.
      以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。
    • span(self, group=0, /)
      For match object m, return the 2-tuple (m.start(group), m.end(group)).
      返回(start(group), end(group))。
    • start(self, group=0, /)
      Return index of the start of the substring matched by group.
      返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。

    更多请查阅:help(re.Match)

    1. re.Pattern对象

    Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。
    Pattern不能直接实例化,必须使用re.compile()进行构造。

    Pattern提供了几个可读属性用于获取表达式的相关信息:

    • flags:The regex matching flags.编译时用的匹配模式。数字形式。
    • groupindex:A dictionary mapping group names to group numbers. 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
    • groups:The number of capturing groups in the pattern.表达式中分组的数量。
    • pattern:The pattern string from which the RE object was compiled.编译时用的表达式字符串。

    更多请查阅:help(re.Pattern)


    两种方式:
    >ipython
    In [1]: import re
    In [3]: type(re.compile(r'course'))
    Out[3]: re.Pattern
    In [4]:
    In [4]: re.match(r'course','course Python3.x').group()
    Out[4]: 'course'
    
    >ipython
    In [1]: str = 'course python 2019'
    In [2]: str.find('one')
    Out[2]: -1
    In [3]: str.find('py')
    Out[3]: 7
    In [4]: str.startswith('python')
    Out[4]: False
    In [5]: str.startswith('course')
    Out[5]: True
    
    In [6]: import re
    In [7]: pa = re.compile(r'2019
    ')
    In [8]: type(pa)
    Out[8]: re.Pattern
    In [9]: re.Pattern.
                        findall()   fullmatch() match()     scanner()   sub()
                        finditer()  groupindex  mro()       search()    subn()
                        flags       groups      pattern     split()
    
    In [9]: help(re.Pattern.match)
    Help on method_descriptor:
    
    match(self, /, string, pos=0, endpos=9223372036854775807)
        Matches zero or more characters at the beginning of the string.
    
    In [10]:
    

    注:r代表原始字符串,最大的作用是避免转义


    Match对象的属性

    1. string 属性:
      获取匹配时使用的字符串对象获取匹配时使用的字符串对象
    >>> m = re.match(r'd+','456abc')
    >>> m.string
    '456abc'
    
    1. re 属性:
      匹配时使用的pattern对象,也就是匹配到内容的正则表达式对象匹配时使用的pattern对象,也就是匹配到内容的正则表达式对象
    >>> m
    <_sre.SRE_Match object at 0x02C8FA68>
    
    >>> m.re
    <_sre.SRE_Pattern object at 0x02D4ECD0>
    
    1. pos属性:
      该属性表示文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法中的同名参数相同
    >>> m.pos
    0
    
    1. endpos属性:
      该属性表示文本中正则表达式结束搜索的索引。值与Pattern.match()和 Pattern.seach()方法中的同名参数相同
    >>> m.endpos
    6
    
    1. lastindex属性:
      该属性表示最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None
    >>> m= re.match(r'a(b)(c)d','abcdef')
    >>> m.lastindex
    2
    
    1. lastgroup属性:
      该属性表示最后一个被捕获的分组别名。如果这个分组没有别名或者没有被捕获的分组,将为None。

    2. group([group1, …]):
      获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编 号也可以使用别名;编号0代表匹配的整个子串;默认返回group(0)
      实例:group函数传多个参数

    p = re.compile('(a(b)c)d')
    m = p.match('abcd')
    resTup = m.group(1,2,1)
    print resTup
    >>>('abc', 'b', 'abc')
    
    1. groups([default=None])
      以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)

    2. start([group=0])
      返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。默认为第0组,即整个字符串

    3. end([group=0])
      返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引)。group默认值 为0,即整个字符串

    4. span([group])
      该方法表示以元组的形式返回 (start(group), end(group)),即某个分组的匹配文字内容在被 匹配字符串的开始索引位置和结束索引位置

    5. expand(template)
      将匹配到的分组代入template中然后返回。template中可以使用id或g、g 引用分组,但不能使用编号0。id与g是等价的;但10将被认为是第10个分组,如果 你想表达1之后是字符’0’,只能使用g<1>0。

    m = re.search(r'(w+)! (w+) (w+)','HMan! How finny!')
    # 将匹配的结果带入 print m.expand(r'resut:3 2 1')  
    >>> resut:finny How HMan
    
    1. groupdict([default=None])
      该函数的作用是,将所有匹配到并且指定了别名的分组,以别名为key,匹配到的字串为value, 存于字典中,然后返回这个字典。如果表达式中未设置别名分组,就会返回一个空字典
    >>> m = re.search(r'(?P<num>d+)(w+)','78fd')
    >>> m.groupdict()
    {'num': '78'}
    

    match()方法

    • 匹配字符串开头的零个或多个字符。返回一个match对象或None。
    • 可选参数pos和endpos分别指定被匹配字符串的开始和结束位置
    In [10]: str
    Out[10]: 'course python 2019'
    
    In [11]: pa.match(str)
    Out[11]: <re.Match object; span=(0, 6), match='course'>
    
    In [12]: ma = pa.match(str)
    
    In [13]: ma
    Out[13]: <re.Match object; span=(0, 6), match='course'>
    
    In [14]: type(ma)
    In [15]: re.Match.
                       end()       group()     lastgroup   pos         span()
                       endpos      groupdict() lastindex   re          start()
                       expand()    groups()    mro()       regs        string
    
    In [15]: ma.group()
    Out[15]: 'course'
    
    In [16]: help(re.Match.group)
    Help on method_descriptor:
    
    group(...)
        group([group1, ...]) -> str or tuple.
        Return subgroup(s) of the match by indices or names.
        For 0 returns the entire match.
    
    In [17]:
    

    group()方法

    • 返回一个字符串或者元组
    • 有括号括起来返回元组,否则返回字符串

    匹配结果在原始字符串的索引位置:span()方法

    In [17]: ma.span()
    Out[17]: (0, 6)
    
    In [18]:
    

    被匹配字符串:string属性

    In [18]: ma.string
    Out[18]: 'course python 2019'
    

    Pattern实例:re属性

    In [19]: ma.re
    Out[19]: re.compile(r'course', re.UNICODE)
    
    In [20]:
    

    忽略大小写:

    In [20]: pa
    Out[20]: re.compile(r'course', re.UNICODE)
    
    In [21]: pa = re.compile('course', re.I)
    
    In [22]: pa
    Out[22]: re.compile(r'course', re.IGNORECASE|re.UNICODE)
    
    IIn [23]: ma = pa.match('Course: Python3.x 
     course:etc...')
    
    In [24]: ma.group()
    Out[24]: 'Course'
    
    In [25]: ma = pa.match('Couse: Python3.x 
     course:etc...')
    
    In [26]: ma.group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-8-ad89060ab833> in <module>
    ----> 1 ma.group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [27]: pa = re.compile('course')
    
    In [28]: pa
    Out[28]: re.compile(r'course', re.UNICODE)
    
    In [29]: ma = pa.match('Couse: Python3.x 
     course:etc...')
    
    In [30]: ma.group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-18-ad89060ab833> in <module>
    ----> 1 ma.group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [31]:
    

    (元)组的形式返回groups()

    In [31]: pa = re.compile(r'(course)', re.I)
    
    In [32]: pa
    Out[32]: re.compile(r'(course)', re.IGNORECASE|re.UNICODE)
    
    In [33]: pa.match('Course: Python3.x 
     course:etc...').group()
    Out[33]: 'Course'
    
    In [34]: pa.match('Course: Python3.x 
     course:etc...').groups()
    Out[34]: ('Course',)
    
    In [35]: pa = re.compile(r'course', re.I)
    
    In [36]: pa
    Out[36]: re.compile(r'course', re.IGNORECASE|re.UNICODE)
    
    In [37]: pa.match('Course: Python3.x 
     course:etc...').group()
    Out[37]: 'Course'
    
    In [38]: pa.match('Course: Python3.x 
     course:etc...').groups()
    Out[38]: ()
    
    In [39]: pa = re.compile(r'course', re.I)
    
    In [40]: pa
    Out[40]: re.compile(r'course', re.IGNORECASE|re.UNICODE)
    
    In [41]: pa.match('Course: Python3.x 
     course:etc...').group()
    Out[41]: 'Course'
    
    In [42]: pa.match('Course: Python3.x 
     course:etc...').groups()
    Out[42]: ()
    
    In [43]: pa = re.compile(r'(course)', re.I)
    
    In [44]: pa
    Out[44]: re.compile(r'(course)', re.IGNORECASE|re.UNICODE)
    
    In [45]: pa.match('Course: Python3.x 
     course:etc...').group()
    Out[45]: 'Course'
    
    In [46]: pa.match('Course: Python3.x 
     course:etc...').groups()
    Out[46]: ('Course',)
    
    In [47]:
    

    关于groups()

    In [52]: ma = pa.match('Course: Python3.x 
     course:etc...')
    
    In [53]: ma
    Out[53]: <re.Match object; span=(0, 6), match='Course'>
    
    In [54]: type(ma)
    Out[54]: re.Match
    
    In [55]: help(re.Match.groups)
    Help on method_descriptor:
    
    groups(self, /, default=None)
        Return a tuple containing all the subgroups of the match, from 1.
    
        default
          Is used for groups that did not participate in the match.
    
    In [56]:
    
    1. 上面方法是先生成判断对象再匹配字符串。下面介绍直接使用match方法:

    2. 直接使用match方法

    In [56]: help(re.match)
    Help on function match in module re:
    
    match(pattern, string, flags=0)
        Try to apply the pattern at the start of the string, returning
        a Match object, or None if no match was found.
    
    
    In [57]:
    

    match()方法

    • 尝试应用字符串开头的模式,返回匹配对象,如果没有找到匹配,则返回None。
    In [57]: ma = re.match(r'course','course python3.x etc..')
    
    In [58]: ma
    Out[58]: <re.Match object; span=(0, 6), match='course'>
    
    In [59]: type(ma)
    Out[59]: re.Match
    
    In [60]: ma.group()
    Out[60]: 'course'
    
    In [61]:
    

    注:这种方式适合匹配次数较少的情况,因为每次匹配都会生成一个Pattern对象。

    
    In [10]: re.
                 A              copyreg     enum            findall     functools
                 L              Match       Pattern         S           split
                 sub            TEMPLATE    UNICODE         ASCII       DEBUG
                 error          finditer    I               LOCALE      match
                 purge          Scanner     sre_compile     subn        template
                 VERBOSE        compile     DOTALL          escape      fullmatch
                 IGNORECASE     M           MULTILINE       RegexFlag   search
                 sre_parse      T           U               X
    
    
    In [10]: str
    Out[10]: 'course python 2019'
    
    In [11]: pa = re.compile(r'2019')
    
    In [12]: pa.match(str)
    
    In [13]: pa.search(str)
    Out[13]: <re.Match object; span=(14, 18), match='2019'>
    
    In [14]: sc = pa.search(str)
    
    In [15]: sc.group
    Out[15]: <function Match.group>
    
    In [16]: sc.group()
    Out[16]: '2019'
    
    In [17]: pa = re.compile(r'course')
    
    In [18]: pa.match(str).group()
    Out[18]: 'course'
    
    In [22]: help(sc.group)
    Help on built-in function group:
    
    group(...) method of re.Match instance
        group([group1, ...]) -> str or tuple.
        Return subgroup(s) of the match by indices or names.
        For 0 returns the entire match.
    
    
    In [23]:
    

    正则表达式语法

    正则表达式语法1:

    字符 匹配
    . 匹配任意(除 )字符
    [] 匹配[]中包含字符串中任一字符
    dD 匹配数字,非数字
    sS 匹配空白( fv),非空白字符
    wW 匹配单词字符[a-zA-Z0-9_],非单词字符

    注:

    1. [...]匹配的是[]中包含字符的任意一个字符,如[ijk]匹配的是i、j、k任一字符;匹配多个字符的情况详下面。
    2. [u4E00-u9FA5]匹配任一汉字,英文空格不是汉字。
    3. [.]匹配的是.,再如[.*]匹配的是.*
    4. [d]匹配的是任意数字,等价于[0-9]
    5. [^...]中的^表示字符类取反
    6. fv分别对应:水平制表符、换行符、回车符、换页符、垂直制表符
    In [3]: import re
    
    In [4]: ma = re.match(r'{[abc]}','{b}')
    
    In [5]: ma.group()
    Out[5]: '{b}'
    
    In [6]: ma = re.match(r'{[abc]}','{d}')
    
    In [7]: type(ma)
    Out[7]: NoneType
    
    In [8]: ma = re.match(r'{[.]}','{d}')
    
    In [9]: ma.group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-9-ad89060ab833> in <module>
    ----> 1 ma.group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [10]: ma = re.match(r'{.}','{d}')
    
    In [11]: ma.group()
    Out[11]: '{d}'
    
    In [16]: ma = re.match(r'{[[abcd]]}','{[d]}')
    
    In [17]: ma.group()
    Out[17]: '{[d]}'
    
    In [18]:
    

    注:如果要匹配的模式包含[]需要转义.

    正则表达式语法2:

    字符 匹配
    * 匹配前一个元素0次或者无限次
    + 匹配前一个元素1次或者无限次
    ? 匹配前一个元素0次或者1次,非贪婪
    {m}/{m,n}/{m,} 匹配前一个元素恰好m次或者至少m次但不多于n次或者至少m次
    *?/+?/?? 匹配模式变为非贪婪(尽可能少匹配字符)
    In [18]: ma = re.match(r'[A-Z][a-z]*','A')
    
    In [19]: ma.group()
    Out[19]: 'A'
    
    In [20]: ma = re.match(r'[A-Z][a-z]','A')
    
    In [21]: ma.group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-21-ad89060ab833> in <module>
    ----> 1 ma.group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [22]: ma = re.match(r'[A-Z][a-z]*','AbcdefgHIJK')
    
    In [23]: ma.group()
    Out[23]: 'Abcdefg'
    
    In [24]:
    
    

    一个例子:

    Python变量命名规则

    • 变量名只能包含字母、数字和下划线。变量名可以字母或下划线开头,但不能以数字开头。
    • 变量名不能包含空格,但可使用下划线来分隔其中的单词。
    • 不要将Python关键字和函数名用作变量名,即不要使用Python保留用于特殊用途的单词,如print。
    • 变量名应既简短又具有描述性。
    • 慎用小写字母l和大写字母O,因给他们可能被人错看成数字1和0;
      注意:应使用小写的Python变量名。在变量名中使用大写字母虽然不会导致错误,但避免使用大写字母是个不错的注意。

    我们重点关注前两点,用正则表达式来描述:

    In [38]: while(True):
        ...:     pa = re.compile(r'[_a-zA-Z][_w]*')
        ...:     str = input("输入字符串:")
        ...:     ma = pa.match(str)
        ...:     if ma != None:
        ...:         print(ma.group())
        ...:
    
    In [44]: while(True):
        ...:     pa = re.compile(r'[_a-zA-Z][_a-zA-Z0-9]*')
        ...:     str = input("输入:")
        ...:     ma = pa.match(str)
        ...:     if ma != None:
        ...:         print(ma.group())
        ...:
    

    44是对38的改进,可以尝试38输入__哈哈仍然匹配成功,而44中匹配得到的是__

    匹配0-99之间的数字:

    In [5]: ma = re.match(r'[1-9]?[0-9]', '0')
    
    In [6]: ma.group()
    Out[6]: '0'
    
    In [7]: ma = re.match(r'[1-9]?[0-9]', '10')
    
    In [8]: ma.group()
    Out[8]: '10'
    
    In [9]: ma = re.match(r'[1-9]?[0-9]', '99')
    
    In [10]: ma.group()
    Out[10]: '99'
    
    In [11]: ma = re.match(r'[1-9]?[0-9]', '100')
    
    In [12]: ma.group()
    Out[12]: '10'
    
    In [13]:
    
    

    匹配指定次数:

    In [21]: re.match(r'[a-z]{2}','haha').group()
    Out[21]: 'ha'
    
    In [22]: re.match(r'[a-z]{2,3}','haha').group()
    Out[22]: 'hah'
    
    In [23]: re.match(r'[a-z]{2,4}','hahaxxxioflsaj').group()
    Out[23]: 'haha'
    
    In [24]: re.match(r'[a-z]{2,4}','ha3ha').group()
    Out[24]: 'ha'
    
    In [25]: re.match(r'[a-z]{2,4}','hah3ha').group()
    Out[25]: 'hah'
    
    In [26]: re.match(r'[a-z]{2,4}','hahx3ha').group()
    Out[26]: 'hahx'
    
    In [27]:
    

    非贪婪模式:*?+???

    In [28]: ma = re.match(r'[0-9][a-z]*','1abcdef').group()
    
    In [29]: re.match(r'[0-9][a-z]*','1abcdef').group()
    Out[29]: '1abcdef'
    
    In [30]: re.match(r'[0-9][a-z]*?','1abcdef').group()
    Out[30]: '1'
    
    In [31]: re.match(r'[0-9][a-z]+?','1abcdef').group()
    Out[31]: '1a'
    
    In [32]: re.match(r'[0-9][a-z]?','1abcdef').group()
    Out[32]: '1a'
    
    In [33]: re.match(r'[0-9][a-z]+','1abcdef').group()
    Out[33]: '1abcdef'
    
    In [34]: re.match(r'[0-9][a-z]??','1abcdef').group()
    Out[34]: '1'
    
    In [35]: re.match(r'[0-9][a-z]?','1abcdef').group()
    Out[35]: '1a'
    
    In [36]:
    
    非贪婪模式

    贪婪匹配的限定符:*+?{n}{n,}{n,m}
    非贪婪是在贪婪限定符后面多加一个?,如下表所示:

    限定符 描述 模式 匹配
    *? 匹配上一个元素零次或多次,但次数尽可能少 d*?.d “.0”,“19.9"和"219.9”
    +? 匹配上一个元素一次或多次,但次数尽可能少 be+? “been中的"be”,bent"中的"be"
    ?? 匹配上一个元素零次或一次,但次数尽可能少 rai??n “ran"和"rain”
    {n}? 匹配前导元素恰好n次 ,d{3}? "1.043.6"中的.043
    {n,}? 匹配上一个元素至少n次,但次数尽可能少 d{2,}? “166”,“29"和"1930”
    {n,m}? 匹配上一个元素的次数介于n和m之间,但次数尽可能少 d{3,5}? “166”,“16546”,“132654"中的"132”,“654”

    测试代码:

    import re
    
    line = ""
    regex_re = ""
    match_obj = re.match(regex_re, line)
    if match_obj:
        print("# line = "%s"" % line)
        print("# regex_re = "%s"" % (regex_re,))
        print("# 贪婪之后:match_obj.group(1)->%s" % match_obj.group(1))
        # print("# match_obj.group()->%s" % match_obj.group())
    

    验证:

    line = "boooooooobaaaaaoooooobbbbbaaabby123"
    regex_re = ".*(b.*b).*"
    # 贪婪:match_obj.group(1)->bb
    match_obj.group()->boooooooobaaaaaoooooobbbbbbby123
    
    
    line = "boooooooobaaaaaoooooobbbbbbby123"
    regex_re = ".*(b.+b).*"
    # 贪婪:match_obj.group(1)->bbb
    match_obj.group()->boooooooobaaaaaoooooobbbbbbby123
    
    
    line = "booooboooooobbbbbbaaaby123"
    regex_re = ".*(b.*b).*"
    # 贪婪:match_obj.group(1)->baaab
    match_obj.group()->booooboooooobbbbbbaaaby123
    
    line = "booooboooooobbbbbbaaaby123"
    regex_re = ".*(b.+b).*"
    # 贪婪:match_obj.group(1)->baaab
    match_obj.group()->booooboooooobbbbbbaaaby123
    
    line = "boooobaaaooobbbaaaaaaby123"
    regex_re = ".*(b.{2,5}b).*"
    # 贪婪:match_obj.group(1)->boooob
    match_obj.group()->boooobaaaooobbbaaaaaaby123
    
    line = "o你f"
    regex_re = "(^o[w]?f$)"
    # 贪婪:match_obj.group(1)->o你f
    
    # 注:group提取的是最外边那个括号
    line = "boobby123"
    regex_re = "((bobby|boobby)123)"
    # 贪婪:match_obj.group(1)->boobby123
    
    
    line = "study in 四川大学"
    regex_re = ".*([一-龥]+大学)"
    # 贪婪:match_obj.group(1)->川大学
    
    line = "study in 四川大学"
    regex_re = ".*?([一-龥]+大学)"
    # 非贪婪:match_obj.group(1)->四川大学
    
    
    line = "of 出生于 1996年"
    regex_re = ".*?([d]+)"
    # 非贪婪:match_obj.group(1)->1996
    line = "of 出生于 1996年"
    regex_re = ".*?(d+)"
    # 非贪婪:match_obj.group(1)->1996
    
    line = "booooooooobby123"
    regex_re = ".*(b.*b).*"
    # 贪婪:match_obj.group(1)->bb
    
    line = "booooooooobby123"
    regex_re = ".*?(b.*b).*"
    # 前非贪婪后贪婪:match_obj.group(1)->booooooooobb
    
    line = "booooooooobby123"
    regex_re = ".*?(b.*?b).*"
    # 非贪婪:match_obj.group(1)->booooooooob
    
    line = "booooooooobby123"
    regex_re = ".*(b.*?b).*"
    # 前贪婪后非贪婪:match_obj.group(1)->bb
    
    line = "booooooooobijkby123"
    regex_re = ".*(b.*?b).*"
    # 前贪婪后非贪婪:match_obj.group(1)->bijkb
    

    正则表达式语法3:边界语法

    字符 匹配
    ^ 匹配字符串开头
    $ 匹配字符串结尾
    A/ 指定字符串必须出现在开头/结尾

    问题引入:

    In [37]: re.match(r'[a-zA-Z]{4,10}@onefine.top','123coding@onefine.top123').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-37-5c2cf60a1190> in <module>
    ----> 1 re.match(r'[a-zA-Z]{4,10}@onefine.top','123coding@onefine.top123').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [38]: re.search(r'[a-zA-Z]{4,10}@onefine.top','123coding@onefine.top123').group()
    Out[38]: 'coding@onefine.top'
    
    In [39]: re.search(r'^[a-zA-Z]{4,10}@onefine.top$','123coding@onefine.top123').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-39-70e4e4e6988c> in <module>
    ----> 1 re.search(r'^[a-zA-Z]{4,10}@onefine.top$','123coding@onefine.top123').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [40]: re.search(r'^[a-zA-Z]{4,10}@onefine.top','123coding@onefine.top123').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-40-3c138c9aac5e> in <module>
    ----> 1 re.search(r'^[a-zA-Z]{4,10}@onefine.top','123coding@onefine.top123').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [41]: re.search(r'^[a-zA-Z]{4,10}@onefine.top$','123coding@onefine.top').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-41-4ca35adfb0df> in <module>
    ----> 1 re.search(r'^[a-zA-Z]{4,10}@onefine.top$','123coding@onefine.top').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [42]: re.search(r'^[a-zA-Z]{4,10}@onefine.top$','coding@onefine.top').group()
    Out[42]: 'coding@onefine.top'
    
    In [43]: re.match(r'^[a-zA-Z]{4,10}@onefine.top$','coding@onefine.top').group()
    Out[43]: 'coding@onefine.top'
    
    In [45]: re.match(r'^[a-zA-Z]{4,10}@onefine.top','coding@onefine.top123').group()
    Out[45]: 'coding@onefine.top'
    
    In [46]:
    

    A/ 指定字符串必须出现在开头/结尾,用法
    指定必须以coding开头,top结尾

    In [52]: re.match(r'A(coding)[w]*@onefine.(top)','coding@onefine.top').group()
    Out[52]: 'coding@onefine.top'
    
    In [53]:
    

    正则表达式语法4:分组匹配

    字符 匹配
    | 匹配左右任意一个表达式
    (ab) 括号中表达式作为一个分组
    <number> 引用编号为number的分组匹配到的字符串,编号从1开始
    (?P<name>) 分组起一个别名name
    (?P=name) 引用别名为name的分组匹配字符串
    In [54]: re.match(r'abc|d','d').group()
    Out[54]: 'd'
    
    In [55]: re.match(r'abc|d','abc').group()
    Out[55]: 'abc'
    
    In [56]: re.match(r'abc|d','c').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-56-dfcd4a662ebe> in <module>
    ----> 1 re.match(r'abc|d','c').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [57]:
    

    匹配0-100的字符串:

    In [57]: re.match(r'[1-9]?d$|100','100').group()
    Out[57]: '100'
    
    In [58]: re.match(r'[1-9]?d$|100','99').group()
    Out[58]: '99'
    
    In [59]: re.match(r'[1-9]?d$|100','1').group()
    Out[59]: '1'
    
    In [60]: re.match(r'[1-9]?d$|100','0').group()
    Out[60]: '0'
    
    In [61]:
    

    匹配多邮箱:

    n [63]: re.match(r'[w]{4,8}@(163|126).com','onefine@126.com').group()
    Out[63]: 'onefine@126.com'
    
    In [64]: re.match(r'[w]{4,8}@(163|126).com','onefine@163.com').group()
    Out[64]: 'onefine@163.com'
    
    In [65]: re.match(r'[w]{4,8}@(163|126).com','onefine@963.com').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-65-afd701da2fb6> in <module>
    ----> 1 re.match(r'[w]{4,8}@(163|126).com','onefine@963.com').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [66]:
    

    XML–引用分组

    In [80]: re.match(r'<([w]+>)[w]+<\1','<img>onefine<img>').group()
    Out[80]: '<img>onefine<\img>'
    
    In [81]: re.match(r'<([w]+>)[w]+</1','<img>onefine</img>').group()
    Out[81]: '<img>onefine</img>'
    
    In [82]:
    

    80写错了,注意上面的\是转义
    正确的是81,但是有了新的发现:

    正则转义

    先看个例子:

    import re 
    
    string = '38' 
    m = re.search('(d+)\\', string) 
    
    if m is not None: 
    print m.group(1) # 结果为:3 
    
    n = re.search(r'(d+)\', string) 
    
    if n is not None: 
    print n.group(1) # 结果为:3
    

    正则表达式字符串需要经过两次转义,这两次分别是上面的“字符串转义”和“正则转义”,个人认为“字符串转义”一定先于“正则转义”。

    1)'\\'的过程:
    先进行“字符串转义”,前两个反斜杠和后两个反斜杠分别被转义成了一个反斜杠;即“\|\”被转成了“|”(“|”为方便看清,请自动忽略)。“字符串转义”后马上进行“正则转义”,“\”被转义为了“”,表示该正则式需要匹配一个反斜杠。

    2)r'\'的过程:
    由于原始字符串中所有字符直接按照字面意思来使用,不转义特殊字符,故不做“字符串转义”,直接进入第二步“正则转义”,在正则转义中“\”被转义为了“”,表示该正则式需要匹配一个反斜杠。

    结论:也就是说原始字符串(即r'...')与“正则转义”毫无关系,原始字符串仅在“字符串转义”中起作用,使字符串免去一次转义。

    分组起别名&引用,即最后两个成对使用:

    In [97]: re.match(r'<(?P<mark>[w]+>)[w]+</(?P=mark)','<img>onefine</img>').group()
    Out[97]: '<img>onefine</img>'
    

    re模块相关方法使用

    模块re中一些重要的函数

    函数 描述
    compile(pattern[, flags]) 根据包含正则表达式的字符串创建模式对象
    search(pattern, string[,flags]) 在字符串中查找模式
    match(pattern, string[,flags]) 在字符串开头匹配模式
    split(pattern, string[,maxsplit=0]) 根据模式来分割字符串
    findall(pattern, string) 返回一个列表, 其中包含字符串中所有与模式匹配的子串
    sub(pat, repl, string[,count=0]) 将字符串中与模式pat匹配的子串都替换为repl
    escape(string) 对字符串中所有的正则表达式特殊字符都进行转义
    C:UsersONEFINE>ipython
    Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)]
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: import re
    
    In [2]: help(re.match)
    Help on function match in module re:
    
    match(pattern, string, flags=0)
        Try to apply the pattern at the start of the string, returning
        a Match object, or None if no match was found.
    
    In [3]: help(re.search)
    Help on function search in module re:
    
    search(pattern, string, flags=0)
        Scan through string looking for a match to the pattern, returning
        a Match object, or None if no match was found.
    

    search()方法:

    • 扫描字符串string,查找模式pattern指定的正则表达式模式,产生匹配的第一个位置,返回相应的Match对象实例,如果字符串中没有位置与模式匹配,则返回None。请注意,这与在字符串中的某处找到零长度匹配不同。
    In [4]: help(re.findall)
    Help on function findall in module re:
    
    findall(pattern, string, flags=0)
        Return a list of all non-overlapping matches in the string.
    
        If one or more capturing groups are present in the pattern, return
        a list of groups; this will be a list of tuples if the pattern
        has more than one group.
    
        Empty matches are included in the result.
    

    findall()方法

    • 返回的所有非重叠的匹配模式 的字符串,如字符串列表。该字符串进行扫描左到右,并匹配以发现的顺序返回。如果模式中存在一个或多个组,返回组列表; 如果模式有多个组,这将是一个元组列表。空结果包含在结果中,除非他们触及另一场比赛的开始。

    例子:

    In [15]: re.search(r':d+','Python3.x:4000 C++:5000 JAVA:4800').group()[1:]
    Out[15]: '4000'
    
    In [18]: re.findall(r':d+','Python3.x:4000 C++:5000 JAVA:4800')
    Out[18]: [':4000', ':5000', ':4800']
    
    In [19]:
    
    In [5]: help(re.compile)
    Help on function compile in module re:
    
    compile(pattern, flags=0)
        Compile a regular expression pattern, returning a Pattern object.
    
    In [6]: help(re.split)
    Help on function split in module re:
    
    split(pattern, string, maxsplit=0, flags=0)
        Split the source string by the occurrences of the pattern,
        returning a list containing the resulting substrings.  If
        capturing parentheses are used in pattern, then the text of all
        groups in the pattern are also returned as part of the resulting
        list.  If maxsplit is nonzero, at most maxsplit splits occur,
        and the remainder of the string is returned as the final element
        of the list.
    

    split()方法

    • 根据模式的出现拆分字符串。如果在模式中使用捕获括号,则模式中所有组的文本也会作为结果列表的一部分返回。
    • 如果maxsplit不为零,则最多发生maxsplit分割,并且字符串的其余部分作为列表的最后一个元素返回。

    例子:

    In [50]: str_2 = "course: Python C C++ C# JAVA,etc"
    
    In [51]: re.split(r':| |,',str_2)
    Out[51]: ['course', '', 'Python', 'C', 'C++', 'C#', 'JAVA', 'etc']
    
    In [52]: re.split(r' :| |,',str_2)
    Out[52]: ['course:', 'Python', 'C', 'C++', 'C#', 'JAVA', 'etc']
    
    In [53]:
    
    In [7]: help(re.sub)
    Help on function sub in module re:
    
    sub(pattern, repl, string, count=0, flags=0)
        Return the string obtained by replacing the leftmost
        non-overlapping occurrences of the pattern in string by the
        replacement repl.  repl can be either a string or a callable;
        if a string, backslash escapes in it are processed.  If it is
        a callable, it's passed the Match object and must return
        a replacement string to be used.
    

    sub()方法

    • 通过用替换repl替换字符串中最左边不重叠出现的模式而获得的字符串。 如果未找到该模式,则字符串将保持不变。 repl可以是一个字符串或一个函数; 如果它是一个字符串,则处理其中的任何反斜杠转义。 也就是 n被转换为单个换行符, r被转换为回车符,等等。 像 j这样的未知转义字符将被单独保留。 反向引用(例如 6)被替换为模式中由组6匹配的子字符串。

    repl为字符串的例子:

    In [24]: str = "course Python videonum: 1000"
    
    In [25]: re.sub(r'd+','9631', str)
    Out[25]: 'course Python videonum: 9631'
    
    In [26]:
    

    与分组一起用:

    In [23]: re.sub(r'defs+([a-zA-Z_][a-zA-Z_0-9]*)s*(s*):',r'static PyObject*
    py_1(void)
    {','def myfunc():')
    Out[23]: 'static PyObject*
    py_myfunc(void)
    {'
    

    repl为函数的例子:

    In [43]: def add(match):
        ...:     val = match.group()
        ...:     num = int(val) + 1
        ...:     return str(num)
        ...:
        ...:
    
    In [44]: str
    Out[44]: 'course Python videonum: 1000'
    
    In [45]: del(str)
    
    In [46]: str_1 = 'course Python videonum: 1000'
    
    In [48]: re.sub(r'd+', add, str_1)
    Out[48]: 'course Python videonum: 1001'
    
    In [49]:
    

    提示:str是Python内置函数。千万不要定义为变量名。错误TypeError: ‘str’ object is not callable字面上意思:就是str不可以被系统调用,其实原因就是:你正在调用一个不能被调用的变量或对象,具体表现就是你调用函数、变量的方式错误。

    In [8]: help(re.escape)
    Help on function escape in module re:
    
    escape(pattern)
        Escape special characters in a string.
    
    
    In [10]: help(re.I)
    Help on RegexFlag in module re object:
    
    class RegexFlag(enum.IntFlag)
     |  RegexFlag(value, names=None, *, module=None, qualname=None, type=None, start=1)
     |
     |  An enumeration.
     |
     |  Method resolution order:
     |      RegexFlag
     |      enum.IntFlag
     |      builtins.int
     |      enum.Flag
     |      enum.Enum
     |      builtins.object
     |
     |  Data and other attributes defined here:
     |
     |  ASCII = <RegexFlag.ASCII: 256>
     |
     |  DEBUG = <RegexFlag.DEBUG: 128>
     |
     |  DOTALL = <RegexFlag.DOTALL: 16>
     |
     |  IGNORECASE = <RegexFlag.IGNORECASE: 2>
     |
     |  LOCALE = <RegexFlag.LOCALE: 4>
     |
     |  MULTILINE = <RegexFlag.MULTILINE: 8>
     |
     |  TEMPLATE = <RegexFlag.TEMPLATE: 1>
     |
     |  UNICODE = <RegexFlag.UNICODE: 32>
     |
     |  VERBOSE = <RegexFlag.VERBOSE: 64>
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from enum.Enum:
     |
     |  name
     |      The name of the Enum member.
     |
     |  value
     |      The value of the Enum member.
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from enum.EnumMeta:
     |
     |  __members__
     |      Returns a mapping of member name->value.
     |
     |      This mapping lists all enum members, including aliases. Note that this
     |      is a read-only view of the internal mapping.
    
    
    In [11]:
    

    Flags标志符

    正则表达式可以包含一些标志修饰符来控制匹配模式,用在正则表达式处理函数中的flag参数中,为可选参数。

    标志 描述
    re.I(IGNORECASE) 忽略大小写
    re.M(MULTILINE) 多行模式,改变’^‘和’$'的行为
    re.S(DOTALL) 改变’.'的行为
    re.X(VERBOSE) 可以给你的表达式写注释

    注:

    • 除以上标志外还有re.L和re.U,但不常用
    • 可以通过使用运算符“|“来指定多个标志,表示同时生效。如
    >ipython
    In [1]: str_1 = 'Hello world'
    In [2]: import re
    
    In [3]: re.search(r'wo..d', str_1, re.I|re.M).group()
    Out[3]: 'world'
    
    In [4]:
    
    re.I(re.IGNORECASE): 表示使匹配时,忽略大小写
    In [1]: import re
    
    In [2]: re.search('a','abc').group()
    Out[2]: 'a'
    
    In [3]: re.search('a','Abc').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-3-94da83bf8997> in <module>
    ----> 1 re.search('a','Abc').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [4]: re.search('a','Abc',re.I).group()
    Out[4]: 'A'
    
    In [5]:
    
    M(MULTILINE): 多行模式,影响(改变)^$的行为
    In [6]: re.search('foo.$', 'foo2
    foo3
    ').group()
    Out[6]: 'foo3'
    
    In [7]: re.search('foo.$', 'foo2
    foo3
    ', re.M).group()
    Out[7]: 'foo2'
    
    In [8]:
    

    疑问:$不包括换行??? 加了M之后匹配第一行的结尾

    S(DOTALL): 影响.的行为,使点.匹配包括换行在内的所有字符
    - make the '.' special character match any character at all, including a newline; without flag, '.' will match anything except a newline.
    
    In [15]: re.search('.', '
    ').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-15-d4cd05f33b46> in <module>
    ----> 1 re.search('.', '
    ').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [16]: re.search('.', '
    ', re.S).group()
    Out[16]: '
    '
    
    In [17]:
    

    注:加S可以匹配包括换行符在内的所有字符

    X(re.VERBOSE): 这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释,使其更可读。
    In [22]: re.search('.  # test', 'onefine', re.X).group()
    Out[22]: 'o'
    
    In [23]: re.search('.# test', 'onefine', re.X).group()
    Out[23]: 'o'
    
    In [24]: re.search('.       # test', 'onefine', re.X).group()
    Out[24]: 'o'
    
    In [25]:  re.search('.  # test', 'onefine').group()
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-25-bffa2d2d5cfc> in <module>
    ----> 1 re.search('.  # test', 'onefine').group()
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    In [26]:  re.search('.  # test', 'o  # test  haha').group()
    Out[26]: 'o  # test'
    
    In [27]:
    

    注:

    • #前面的空格都无效
    • 当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之后。
    • 它也可以允许你将注释写入 RE,这些注释会被引擎忽略;
    • 注释用 #号 来标识,不过该符号不能在字符串或反斜杠之后。


    综合
    line = "XXX出生于1996年6月"
    line = "XXX出生于1996/6/1"
    line = "XXX出生于1996-6-1"
    line = "XXX出生于1996-06-01"
    line = "XXX出生于1996-06"
    regex_str = ".*出生于(d{4}[年/-]d{1,2}([月/-]d{1,2}|[月/-]$|$))"
    
  • 相关阅读:
    举荐一个源代码站—优越源代码
    [转载]如虎添翼Sybase数据库标题年夜搜罗2
    [转载]Sybase ASA中盘问元信息的几个常用SQL函数
    [转载]有关Sybase ASE数据库的滥觞
    [转载]Sybase ASA9/ASA10的运用体例
    [转载]Sybase数据库简介(初学者必看)(5)
    [转载]如虎添翼Sybase数据库效果大大包罗5
    [转载]Sybase数据库简介(初学者必看)(3)
    [转载]Sybase数据库简介(初学者必看)(2)
    [转载]Sybase数据库简介(初学者必看)(4)
  • 原文地址:https://www.cnblogs.com/onefine/p/10499367.html
Copyright © 2011-2022 走看看