应用场景:

  • 测试字符串内的模式。 例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
  • 替换文本。 可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
  • 基于模式匹配从字符串中提取子字符串。 可以查找文档内或输入域内特定的文本。

 

python应用模块:

re库

  • Both patterns and strings to be searched can be Unicode strings (str) as well as 8-bit strings (bytes). However, Unicode strings and 8-bit strings cannot be mixed: that is, you cannot match a Unicode string with a byte pattern or vice-versa; similarly, when asking for a substitution, the replacement string must be of the same type as both the pattern and the search string.

 

字符规则:

  1. 匹配单个任何字符,除了换行符:.

    • re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
  2. 转义字符:\将下一个字符标记为一个特殊字符、或一个原义字符。

    例如:

    转成特殊字符:'\'字符+ 'n'字符,变成'\n'成为换行符。

    转成原义字符: '\\'匹配 "\""\(" 则匹配 "("

  3. 匹配数字字符:\d。等价于[0-9]

  4. 匹配非数字字符:\D

  5. 匹配字母和数字及下划线:\w。(小写w)

  6. 匹配非字母、数字、下划线:\W。(大写w)

  7. 匹配空白字符:\s。包括空格、制表符、换页符等等,等价于 [ \t\n\r\f]。

  8. 匹配任何非空白字符:\S

  9. 在指定字符范围内匹配单个字符:[]

    • ==[^...]代表匹配不在[]中的字符==。
    [abc] //匹配a或b或c
    [a-z] //匹配所有的小写字母 
    [A-Z] //匹配所有的大写字母 
    [a-zA-Z] //匹配所有的字母 
    [0-9] //匹配所有的数字 
    [0-9\.\-] //匹配所有的数字,句号和减号 
    [ \f\r\t\n] //匹配所有的白字符
    [(+*)] //匹配(、+、*、) 4个字符。在这里面特殊字符会失去特殊意义
    [^abc] //匹配除了a,b,c之外的字符
    
  10. 匹配左或右:|一旦左边匹配成功,右边就不再进行匹配。

  11. 提取子串分组:()。匹配完全后,括号内的内容可以被获取。

    • 如果想要多个分组,可用多个括号分别括起其匹配模式。

    • (?...)匹配模式中的?并没含义,只是表明使用扩展模式。其后的紧接的字符决定整个匹配模式的含义和语法结构。

      • (?:...):紧接的字符是:。该匹配模式表明和正常(...)一样匹配,但不会将其捕获结果分组。即.group()不会有其分组。

      • (?aiLmsux):紧接的是可以'a', 'i', 'L', 'm', 's', 'u', 'x'中任意一个或多个字符。该匹配模式的结果是匹配空字符串。如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在re.compile()中传递 flag 参数

      • (?P<name>...):紧接的字符是P<name>。尖括号是自定义的分组名(类似字典的键)。尖括号后面接的是匹配模式。如果匹配成功,可通过.group(name)获取该分组内容。

      • (?P=name):紧接的字符是大写P=name。名字是表达式中前面匹配分组所定义的分组名。该分组所捕获的内容必须要与前面自定义分组捕获的字符完全一致才算匹配成功。.group()分组不会有该组数字。

      #eg:
      >>> test1 = re.search(r'(?P<gp>A.)bc(de)(?P=gp)', 'AabcdeAa')
      >>> test2 = re.search(r'(?P<gp>A.)bc(de)(?P=gp)', 'AabcdeAb')
      >>> test1
      <re.Match object; span=(0, 8), match='AabcdeAa'>
      >>> test2
      >>> test1.group(1)
      'Aa'
      >>> test1.group(2)
      'de'
      >>> test1.group(3)
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      IndexError: no such group
      
      • (?=...):紧接的字符是=。又名lookahead assertion断言当前位置,如能匹配时成功,否则失败。该匹配模式只断言,不会消耗字符。所以其后的匹配模式还能匹配到当前位置的字符。
      >>> s = re.search(r'(?=200)\d*', 'abcd20001234')
      >>> s
      <re.Match object; span=(4, 12), match='20001234'>
      
      • (?<=...):紧接的字符是<=。又名lookbehind assertion断言在当前位置前面的字符,如能匹配时成功,否则失败。该匹配模式是先把\d*匹配完。然后在断言其字符串前面的字符是否成功。
      >>> s = re.search(r'(?<=200)\d*', 'abcd20001234')
      >>> s
      <re.Match object; span=(7, 12), match='01234'>
      
      • (?#...):第一个字符是#。里面的匹配内容会被忽略。
  12. 定位匹配:

    • 匹配字符串的开头:^。等同于\A
    • 匹配字符串的末尾:$。等同于\Z
    • 匹配一个单词边界:\b。作用于单词的开头或结尾处的空字符。例如, 'er\b' 可以匹配never中的er,但不能匹配 verb中的 er
    • 匹配非单词边界:\B,即其余匹配字符应为该单词的非边界部分。例如, 'er\b' 可以匹配 verb中的 er,但不能匹配never中的er
  13. 出现次数

    The '*', '+', and '?' qualifiers are all greedy; they match as much text as possible,<.*> is matched the entire string '<a> b <c>'.

    Adding ? after the qualifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched.RE <.*?> will match only '<a>'.

    • 匹配前面的子表达式零次或多次:*
    • 匹配前面的子表达式一次或多次:+
    • 匹配前面的子表达式零次或一次:?
    • 匹配确定的 n 次:{n}
    • 至少匹配n 次:{n,}
    • 最少匹配 n 次且最多匹配 m 次:{n,m}

 

正则表达式修饰符 - 可选标志

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。多个修饰符可以通过|组合 。如 re.I | re.M 被设置成 I 和 M 标志:

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

 

建议匹配步骤

如果用同一模式去做多次匹配和搜索操作的话,最好先编译正则表达式,然后再重复使用它。

  1. 编译正则表达式字符串

    import re
    
    datepat = re.compile(r'\d+/\d+/\d+')
    
    • 使用python的r前缀就会变成原始raw字符串,就不用考虑转义的问题。
  2. 用编译后的正则表达式去匹配字符串

    >>> m = datepat.findall('11/27/2012abcdef')
    
    >>> m
    ['11/27/2012']
    
    

 

正则表达式常用方法

1. re.compile(pattern, flags=0):编译正则表达式,可用于其他方法作为匹配模式。

>>>import re
>>> datepat = re.compile(r'\d+/\d+/\d+')

 

2. re.search(pattern, string, flags=0):扫描整个字符串,返回第一个成功匹配的match对象,否则返回None

>>> result = datepat.search('d11/27/2012abcdef')

>>>result
<re.Match object; span=(1, 11), match='11/27/2012'>

 

3. re.match(pattern, string, flags=0):从字符串的起始位置匹配。如果匹配成功,返回一个Match对象,否则返回None

  • Note that even in MULTILINE mode, re.match() will only match at the beginning of the string and not at the beginning of each line.

    If you want to locate a match anywhere in string, use search() instead

>>> result = datepat.match('d11/27/2012abcdef')

>>>print(result)
None

 

4. re.fullmatch(pattern, string, flags=0):从字符串的起始位置匹配。如果完全匹配成功,返回一个Match对象,否则返回None

 

5. re.split(pattern, string, maxsplit=0, flags=0):根据正则表达式来切分字符串。适用于更复杂的切分方法,比直接用str.split()更灵活。

>>> line = 'asdf fjdk; afed, fjek,asdf, foo'
>>> re.split(r'[;,\s]\s*', line)
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

如果匹配模式中包含捕获分组

  • 那么括号里面所匹配到的字符也会出现在结果列表中

    >>> line = 'asdf fjdk; afed, fjek,asdf, foo'
    >>> fields = re.split(r'(;|,|\s)\s*', line)
    >>> fields
    ['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']
    
  • 如果括号里面匹配模式能匹配到字符串的第一个字符,则第一个是空字符

    >>> re.split(r'(\W+)', '...words, words...')
    ['', '...', 'words', ', ', 'words', '...', '']
    >>> re.split(r'\b', 'Words, words, words.')
    ['', 'Words', ', ', 'words', ', ', 'words', '.']
    

 

6. re.sub(pattern, repl, string, count=0, flags=0):按照匹配模式匹配到的字符串按照repl替换。如果匹配模式没找到,则不作任何修改。repl可以是字符串或者是一个函数。

 

7. re.findall(pattern, string, flags=0):以列表的形式返回不重复匹配的所有字符。从左往右扫描,按顺序匹配。

  • 空匹配也会包含在列表结果里。

 

8. re.finditer(pattern, string, flags=0):以迭代器的形式返回不重复匹配的字符。从左往右扫描,按顺序匹配。

 

Match对象

match()search()方法如果匹配成功,会返回一个match对象。通过访问该对象获取匹配结果。

Match.group([group1, ...]):返回一个或多个分组。

  • .group(0)是返回match对象的所有分组的匹配结果
  • 默认从数字1开始返回第一个分组结果。eg·:m.group(1)
  • match对象有__getitem__方法,可以更直接使用索引的方式获取。eg:m[1]

  • 如果使用正则匹配时给分组自定义组名,还可以使用自定义组名获取。eg:m.group('first_name')

Match.groups():以元组的方式返回所有的分组。

Match.groupdict():以字典的方式返回所有的分组。前提是正则匹配时要定义组名

 

参考例子

待补充


There are 0 comments