美文网首页
Python 中正则表达式全部语法速查

Python 中正则表达式全部语法速查

作者: 等不到你6343 | 来源:发表于2020-09-10 20:41 被阅读0次

    正则表达式

    正则语法

    特性

    • 正则表达式可以拼接,如果A和B都是正则表达式,那么 AB也是正则表达式.如果字符串p匹配A并且另一个字符串q匹配B, 那么pq可以匹配 AB.这就构成了由简单构建复杂的基础.除非:
      • A或者B包含低优先级操作
      • A和B存在边界条件
      • 存在命名组引用。

    字符

    元字符 : 特殊字符

    它们不匹配自己,在正则中具有其它的意义,匹配自己需要转义.

    元字符的完整列表:

    基础字符
    字符 功能
    \ 转义
    [ ] 匹配一类单个字符,在里面的字符除了[- ^ \s \S \d \D \w \W] 都是普通字符
    () 分组.与数学中括号的作用大致相同.将括号内的内容视作一个独立字符或部分.
    零宽度断言

    它们不用来代表字符,用来实现一些特殊的匹配功能

    字符 功能
    | “or”运算符,优先级非常低.存在短路现象
    ^ [ ]内字符集的取反,或写在模式开头,代表以模式开头.MULTILINE 模式中,可以匹配在换行符之后的字符串内的任何位置。
    $ 写在模式结尾,代表以模式结尾.只有\n在结尾也算匹配成功
    \A 不在 MULTILINE 模式时,和 ^ 相同.MULTILINE 模式中,\A 仍然只在字符串开头匹配
    \Z 只匹配字符串尾
    \b 匹配完整单词,前后都是非字母数字字符:r'\bclass\b'.必须使用r'',因为Python会把\b解析为退格
    \B 不在字边界时才匹配
    \number 匹配数字代表的组合
    重复限定
    • 它们不能直接嵌套使用,避免了非贪婪后缀 ? 修饰符,和其他实现中的修饰符产生的多义性
    • 可以使用括号包围再进行嵌套
    字符 功能
    . 匹配一个任意字符一次,是否包括换行符取决于DOTALL参数
    {m,n} 匹配前一个字符的出现次数范围, m<=出现次数<=n. 可以缺省其中一个,视为0或无上限
    {m} 匹配前一个字符的m个重复,少于 m 的话就会导致匹配失败
    * {0,} 它的匹配是 贪婪的,先尽可能多地匹配,不成功再回退.
    + {1,}
    ? {0,1}, 代表一个可选字符.还可做非贪婪后缀修饰符

    一类单个字符

    语法 含义 同义替换
    [abc] a 或 b 或 c a|b|c
    [a-z] a-z 所有字符
    [^5] 除了5所有的字符
    \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_ ]

    Python 中的正则 -- re 模块

    参考链接

    Python re模块 官方文档

    Python 正则入门 官方教程

    特性

    • 模式和被搜索的字符串既可以是 Unicode 字符串str ,也可以是8位字节串bytes.但不能混用.
    • 反斜杠灾难: python字符串中和正则中 / 都是转义字符,所以需要二次转义.正则中一个 '/' 在字符串中就会写成 '////'.解决方法是尽量使用 Python 的原始字符串表示法,在字符串前加 r ,例如: r'/'
    • 第三方模块regex, 提供了与标准库re模块兼容的API接口, 同时还提供了额外的功能和更全面的Unicode支持
    • 正则表达式模式被编译成一系列字节码,然后由用 C 编写的匹配引擎执行.
    • 适当选择代码和正则: 虽然 Python 代码比精心设计的正则表达式慢,但它也可能更容易理解.
    • 是Python附带的C扩展模块

    API

    编译正则

    import re
    p = re.compile('ab*')
    
    //还可以接受一个可选的flag参数,用于启用各种特殊功能和语法变体
    re.compile('ab*',re.IGNORECASE)
    
    编译标志(选项)
    标志(前加 re.) 缩写 含义
    ASCII A 使几个转义如 \w\b\s\d 仅与具有相应的 ASCII 字符匹配而不是完整匹配Unicode
    DOTALL S 使 . 匹配任何字符,包括换行符,否则不包括换行符
    IGNORECASE I 忽略大小写
    LOCALE L 进行区域设置感知匹配,应用于考虑到语言差异的程序
    MULTILINE M 多行匹配,将每行(以换行符为分割)视作单独的字符串.
    VERBOSE X 忽略正则中不在字符类里的空格将被忽略.使用户可以使用空格,缩进,注释(#)美化正则的格式
    DEBUG 显示编译时的debug信息
    # VERBOSE
    pat = re.compile(r"""
     \s*                 # Skip leading whitespace
     (?P<header>[^:]+)   # Header name
     \s* :               # Whitespace, and a colon
     (?P<value>.*?)      # The header's value -- *? used to
                         # lose the following trailing whitespace
     \s*$                # Trailing whitespace to end-of-line
    """, re.VERBOSE)
    

    匹配方法

    正则对象的方法和属性
    方法/属性 - 正则编译后的对象.方法名() 功能
    match('字符串'[,起始位置[,结束位置]]) 从字符串开头开始匹配,返回匹配对象
    search('字符串'[,起始位置[,结束位置]]) 找到第一个匹配成功的子字符串,返回匹配对象
    findall('字符串'[,起始位置[,结束位置]]) 找到并用列表返回所有匹配的子字符串
    finditer('字符串'[,起始位置[,结束位置]]) 找到并返回所有匹配成功的匹配对象的iterator
    fullmatch('字符串'[,起始位置[,结束位置]]) 对被查找串的完整匹配,相当于加了[^...$],返回匹配对象
    split('字符串',最大分割数=0) 在正则匹配的所有地方将其拆分为列表.默认分割所有.就地
    sub('表达式','字符串',替换次数=0) 替换匹配到的位置,默认替换所有.就地
    subn('表达式','字符串',替换次数=0) sub() 相同,但返回新字符串和替换次数.就地
    flags 标记 参数 选项
    groups 捕获组合的数量
    groupindex 命名捕获组的字典,如果没有命名捕获组则字典为空
    pattern 编译对象的原始样式字符串
    模块的顶级方法
    • 顶级函数允许同时传入正则表达式和要匹配的字符串,返回值和re.compile下方法的返回值相同

    • 但是如果需要多次匹配,且正则表达式相同,则会进行很多次不必要的编译

    • 每个函数还能在后面传入一个可选的标志参数,只能有一个标志

    方法/属性 - re.方法名() 功能
    match('表达式','字符串',标志) 从字符串开头开始匹配,返回匹配对象
    search('表达式','字符串',标志) 找到第一个匹配成功的子字符串,返回匹配对象
    findall('表达式','字符串',标志) 找到并用列表返回所有匹配的子字符串
    finditer('表达式','字符串',标志) 找到并返回所有匹配成功的匹配对象的iterator
    fullmatch('表达式','字符串',标志) 对被查找串的完整匹配,相当于加了[^...$],返回匹配对象
    split('表达式','字符串',切割次数=0,标志) 在正则匹配的所有地方将其拆分为列表.默认分割所有.就地
    sub('表达式','替换内容','字符串',替换次数=0,标志) 替换匹配到的位置,默认替换所有.就地
    subn('表达式','替换内容','字符串',替换次数=0,标志) sub() 相同,但返回新字符串和替换次数.就地
    escape('表达式') 将字符串中出现的正则元字符进行转义
    purge() 清除正则表达式缓存
    error(*msg*, *pattern=None*, *pos=None*) 返回一个生成的编译错误异常

    匹配(结果)对象

    可以给group(),start(),end(),span()传入参数分组的序号,以获取模式中特定分组匹配到的内容.默认参数为0.

    组从0开始从左到右编号,它始终存在.要确定编号,只需计算从左到右的左括号字符.

    方法/属性 - m.方法名() 功能
    group(分组引用1,引用2...) 返回指定分组引用(数字和命名引用)匹配到的字符串,默认为引用0,即全局匹配结果
    __getitem__(分组引用) 等价于m.group(g),允许更方便的引用一个匹配
    groups(分组未匹配到内容的默认值=None) 返回一个元组,其中包含所有子组的字符串,从1开始所有子组
    groupdict(分组未匹配到内容的默认值=None) 返回一个包含所有的命名子组的字典
    start(分组引用=0) 返回匹配成功的开始位置,否则返回 -1
    end(分组引用=0) 返回匹配成功的结束位置,否则返回 -1
    span(分组引用=0) 返回元组: ( 开始位置 , 结束位置 ),未匹配到返回 ( -1,-1 )
    expand('转义模板') 将结果集合中的元素,根据数字和命名引用填入到转义模板字符串的指定位置
    pos 正则引擎开始搜索的索引位置
    endPos 正则引擎结束搜索的索引位置
    lastindex 最后一个匹配的组的数字引用,如果没有则为None
    lastgroup 最后一个匹配的命名组的名字,如果没有则为None
    re 返回产生这个实例的正则对象
    string 返回被匹配的字符串
    import re
    
    # 一个处理匹配结果的小例子
    m=re.compile('[a-z]+').match('string goes here')
    print(m.group() if m else "匹配失败")  #根据结果m决定后续操作
    #"string"
    
    
    
    # 一个完整的例子
    pattern = re.compile(r'(\w+) (\w+) (?P<word>.*)')
    match = pattern.match('I love you!')
    
    print("match.group(1,2):",match.group(1,2))
    print("match[1]:",match[1])
    print("match.groups():",match.groups())
    print("match.groupdict():",match.groupdict())
    print("match.start(2):",match.start(2))
    print("match.end(2):",match.end(2))
    print("match.span(2):",match.span(2))
    print("match.expand(r'\\2 \\1 \\3'):",match.expand(r'\2 \1 \3'))
    print("match.pos:",match.pos)
    print("match.endpos:",match.endpos)
    print("match.lastindex:",match.lastindex)
    print("match.lastgroup:",match.lastgroup)
    print("match.re:",match.re)
    print("match.string:",match.string)
    
    # match.group(1,2): ('I', 'love')
    # match[1]: I
    # match.groups(): ('I', 'love', 'you!')
    # match.groupdict(): {'word': 'you!'}
    # match.start(2): 2
    # match.end(2): 6
    # match.span(2): (2, 6)
    # match.expand(r'\2 \1 \3'): love I you!
    # match.pos: 0
    # match.endpos: 11
    # match.lastindex: 3
    # match.lastgroup: word
    # match.re: re.compile('(\\w+) (\\w+) (?P<word>.*)')
    # match.string: I love you!
    

    分组扩展

    基本操作
    • 组从0开始编号
    • 组0始终存在,表示整个正则
    • 匹配对象方法以0为默认参数
    • 子组从左到右从1向上编号。
    • 组可以嵌套,要确定编号只需计算从左到右的左括号字符
    p = re.compile('(a)b')
    m = p.match('ab')
    m.group()  #或者 m.group(0)
    #'ab'
    
    
    
    p = re.compile('(a(b)c)d')
    m = p.match('abcd')
    
    m.group(0)
    # 'abcd'
    m.group(1)
    # 'abc'
    m.group(2)
    # 'b'
    
    m.group(2,1,2)
    # ('b', 'abc', 'b')
    
    m.groups()
    # ('abc', 'b')
    
    分组扩展的方式设置参数

    (?参数)

    • 参数: 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一个或多个
    • 标记应该在表达式字符串的首位
    给patten的一部分设置参数

    (?a:表达式)

    (?aiLmsux-imsx:表达式)

    注释

    (?#注释内容)

    捕获组 -> 命名组
    用组名获取特定匹配结果

    (?P<组名>表达式) + result.group('组名') :

    #匹配一个单词
    p = re.compile(r'(?P<word>\b\w+\b)')
    result = p.search('(((( Lots of punctuation )))')
    
    result.group('word')  # 或者result.group()
    #'Lots'
    
    
    
    #匹配一个时间对象
    InternalDate = re.compile(r'INTERNALDATE "'
            r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'
            r'(?P<year>[0-9][0-9][0-9][0-9])'
            r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
            r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
            r'"')
    ......
    m.group('zonem')
    
    在正则后面引用前面的组

    (?P<组名>表达式) + (?P=<组名>) :

    p = re.compile(r'\b(?P<word>\w+)\s+(?P=word)\b')
    p.search('Paris in the the spring').group()
    # 'the the'
    
    传递到 re.sub() 里的 repl 参数中
    非捕获组

    (?:表达式)

    • 对部分值进行匹配但不作为结果,也不会分配组号,当然也不能在表达式和程序中做进一步处理
    • 除了无法检索组匹配内容的事实外,非捕获组的行为与捕获组完全相同
    • 可以在里面放任何东西,用重复元字符重复它
    • 可以用它添加新组而不更改所有其他组的编号方
    import re
    match = re.match(r"(?P<python>123)(?:456)(789)","123456789")
    if match:
        print(match.group("python"))#123
        print(match.groups())#('123', '789')
        
        
    re.findall("industr(?:y|ies)","industryOpqindustries")
    # ['industry', 'industries']
    
    零宽度断言组 - 向前(右)
    • 不代表字符,不会推进匹配过程
    • 只用来对前面的字符进行额外的验证
    • 验证通过后,还可以从断言组开始位置继续向后匹配
    正面 - 类似于 if

    (?=表达式)

    • 类似于 if
    #参考:判断一个字符串是否为[文件名.扩展名]的形式
    '.*[.].*$'
    
    #判断一个字符串是否为[文件名.扩展名]的形式,且扩展名为[bat]
    #在这一应用中而这效果一样,但第二种写法没必要,只是为了说明功能
    #第二种写法在匹配完[bat]后又退回到了[bat]的前面重新判断[.]后的后缀格式
    match = re.match(".*[.]bat$","sample.batch")
    match = re.match(".*[.](?=bat$)[^.]*$","sample.batch")
    
    负面 - 类似于 if not

    (?!表达式)

    #判断一个字符串是否为[文件名.扩展名]的形式,且扩展名不为[bat/exe]
    match = re.match(".*[.](?!bat$|exe$)[^.]*$","sample.batch")
    
    零宽度断言组 - 向回(左)
    • 和向前断言类似
    正面

    (?<=表达式)

    负面

    (?<!表达式)

    三元零宽度断言组 - 向回

    (?(id/name)yes-pattern|no-pattern)

    修改方法

    split()
    p = re.compile(r'\W+')
    
    p.split('This is a')
    # ['This', 'is', 'a']
    
    p.split('This is a',1)
    # ['This', 'is a']
    
    
    
    # 正则中如果有使用捕获括号,则它们的内容也将作为结果列表的一部分返回.
    p = re.compile(r'\W+')
    p.split('This... is a test.')
    # ['This', 'is', 'a', 'test', '']
    
    p2 = re.compile(r'(\W+)')
    p2.split('This... is a test.')
    # ['This', '... ', 'is', ' ', 'a', ' ', 'test', '.', '']
    
    sub()
    p = re.compile('(blue|white|red)')
    
    p.sub('colour', 'blue socks and red shoes')
    # 'colour socks and colour shoes'
    
    p.sub('colour', 'blue socks and red shoes', count=1)
    # 'colour socks and red shoes'
    
    
    
    # 仅当空匹配(*)与前一个空匹配不相邻时,才会进行替换
    p = re.compile('x*')
    p.sub('-', 'abxd')
    # '-a-b--d-'
    
    
    # replacement中的转义:
    # 如果 replacement 是一个字符串,则处理其中的任何反斜杠转义。 也就是说,\n 被转换为单个换行符,\r 被转换为回车符,依此类推。 诸如 \& 之类的未知转义是孤立的
    # 后向引用,例如 \6,被替换为正则中相应组匹配的子字符串。 这使你可以在生成的替换字符串中合并原始文本的部分内容
    #这个例子匹配单词 section 后跟一个用 {,} 括起来的字符串,并将 section 改为 subsection
    p = re.compile('section{ ( [^}]* ) }', re.VERBOSE)
    p.sub(r'subsection{\1}','section{First} section{second}')
    # 'subsection{First} subsection{second}'
    
    
    
    # replacement中引用由 (?P<name>...) 语法定义的命名组:
    # \g<name> 将使用名为 name 的组匹配的子字符串
    # \g<number> 使用相应的组号
    # \g<2> 等同于 \2
    # \20 将被解释为对组 20 的引用
    # 以下替换都是等效的,但使用所有三种变体替换字符串:
    p = re.compile('section{ (?P<name> [^}]* ) }', re.VERBOSE)
    p.sub(r'subsection{\1}','section{First}')
    p.sub(r'subsection{\g<1>}','section{First}')
    p.sub(r'subsection{\g<name>}','section{First}')
    # 'subsection{First}'
    
    
    
    # replacement 也可以是一个函数,它可以为你提供更多控制
    # 如果 replacement 是一个函数,则为 pattern 的每次非重叠出现将调用该函数
    # 在每次调用时,函数都会传递一个匹配的 匹配对象 参数,并可以使用此信息计算所需的替换字符串并将其返回。
    # 在以下示例中,替换函数将小数转换为十六进制:
    def hexrepl(match):
        value = int(match.group())
        return hex(value)
    
    p = re.compile(r'\d+')
    p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
    # 'Call 0xffd2 for printing, 0xc000 for user code.'
    
    
    
    # 使用模块级别 re.sub() 函数时,模式作为第一个参数传递。
    # 图案可以作为对象或字符串提供;如果需要指定正则表达式标志,则必须使用模式对象作为第一个参数,或者在模式字符串中使用嵌入式修饰符,# sub("(?i)b+", "x", "bbbb BBBB")
    # 返回 'x x'
    
    subn()
    p = re.compile('(blue|white|red)')
    
    p.subn('colour', 'blue socks and red shoes')
    # ('colour socks and colour shoes', 2)
    
    p.subn('colour', 'no colours at all')
    # ('no colours at all', 0)
    

    常见问题 - 陷阱

    不用正则进行简单字符串替换

    如果你匹配固定字符串或单个字符类,如果你匹配固定字符串或单个字符类,并且你没有使用任何re功能,例如IGNORECASE标志,那么正则表达式的全部功能可能不是必需的。 字符串有几种方法可以使用固定字符串执行操作,它们通常要快得多,因为实现是一个针对此目的而优化的单个小 C 循环,而不是大型、更通用的正则表达式引擎。

    • 单个子串替换,用replace()替换re.sub().为了避免对单词的部分进行替换,模式必须是 \bword\b,以便要求 word 在任何一方都有一个单词边界。这使得工作超出了 replace() 的能力。
    • 将多个字符替换为其它多个字符或删除,使用translate()替换re.sub()

    在转向re模块之前,请考虑是否可以使用更快更简单的字符串方法解决问题

    区别search()match()

    • 总体来说search()更强一些
    • 不要偷懒在match()pattern开头加入.*来直接代替search()的功能.这样做会使编译器对search()的一些优化无法发挥作用,降低来效率.
    • search()中,可以用 '^' 作为开始来限制匹配到字符串的首位
    • MULTILINE多行模式中函数match()只匹配字符串的开始,但使用 search()和以 '^' 开始的正则表达式会匹配每行的开始

    贪婪与非贪婪

    正则默认是贪婪模式(匹配为尽可能 的文字):

    s = '<html><head><title>Title</title>'  #32个字符
    print(re.match('<.*>', s).group())
    # '<html><head><title>Title</title>'
    
    使用非贪婪的限定符

    非贪婪:匹配为尽可能少的文字

    *?+???{m,n}?

    避免用正则解析HTML

    使用正则表达式解析 HTML 或 XML 很痛苦。HTML 和 XML 有特殊情况会破坏明显的正则表达式;当你编写正则表达式处理所有可能的情况时,模式将非常复杂。使用 HTML 或 XML 解析器模块来执行此类任务

    -- 完 --

    相关文章

      网友评论

          本文标题:Python 中正则表达式全部语法速查

          本文链接:https://www.haomeiwen.com/subject/kshmektx.html