python的正则表达式

re模块

re模块是python中处理正则表达式的一个模块,通过re模块的方法,把正则表达式pattern编译成正则对象,以便使用正则对象的方法。

正则语法

首先推荐一个在线的正则表达式验证调试网站regular expressions 101。支持pythonjavascriptpythongolang4种语言的正则语法。使用时注意勾选正确的语言。
正则表达式中的字符分为普通字符元字符,通过普通字符和元字符组合成一个特定匹配规则的表达式。除元字符之外的都是普通字符。下面介绍部分元字符。

  • 单个字符匹配
    . 匹配换行符\n之外的任意一个字符。
    [...] 表示一个字符集集合。被匹配的文本对应位置可以是这个字符集合中指定的任意字符。
    [^...] 表示匹配除该字符集合指定的字符外的其它所有字符中的任意一个。
    \ 转义字符,可以用来改变特殊字符的原有含义。
  • 预定义字符集
    \d 数字 [0-9]
    \D 非数字 [^\d]
    \s 空白字符 [<空格>\t\r\n\f\v]
    \S 非空白字母 [^\s]
    \w 单词字符 [A-Za-z0-9]
    \W 非单词字符 [^\w]
  • 字符次数匹配
    * 匹配前一个字符0或无限次
    + 匹配前一个字符1或无限次
    ? 匹配前一个字符0或1次
    {m} 匹配前一个字符m次
    {m, n} 匹配前一个字符m至n次。
    *? + ???(m,n)? 使变成非贪婪模式
  • 边界匹配
    ^ 匹配字符串开头。多行模式下匹配每一行的开头。
    $ 匹配字符串末尾。多行模式下匹配每一行的末尾。
    \A 仅匹配字符串开头。
    \Z 仅匹配字符串末尾。
    \b 匹配\w和\W之间。
    \B [^\b]
  • 逻辑与分组
    | 表示逻辑或,代表它左右两边的表达式会任意匹配一个。总是优先匹配左边的表达式,若匹配成功则跳过右边的表达式匹配。若|没有出现在()中,则它的有效范围是整个正则表达式。
    (...) 被括起来的表达式表示一个分组,且每一个分组都有一个正整数编号,从表达式开始每遇到一个分组的左括号,分组编号就+1,。另外,分组表达式作为一个整体,后面可接表示词次数的字符。分组表达式中的|仅在该分组中有效。
    (?P<NAME...>) 表示一个分组,除了原有的分组编号外,又指定了一个分组名称。
    \<number> 引用编号为<number>的分组所匹配到的字符串。
    (?P=name) 引用名称为name的分组所匹配到的字符串。
  • 特殊构造
    (?:...) (…)的不分组版本,用于使用|或后接数量词。
    (?#...) #后的内容将作为注释被忽略。
    (?=...) 后面的字符串内容需要匹配表达式才能成功匹配。不消耗字符串的内容。
    (?<=...) 前面的字符串内容需要匹配表达式才能成功匹配。不消耗字符串的内容。
    (?!...) 后面的字符串内容需要不匹配表达式才能成功匹配。不消耗字符串内容。
    (?<!...) 前面的字符串内容需要不匹配表达式才能成功匹配。不消耗字符串内容。
    (?iLmsux)
    (?(id/name)yes-pattern|no-pattern) 编号为id或别名为name的分组匹配到字符,则需要匹配yes-pattern表达式,否则需要匹配no-pattern表达式。|no-pattern可以省略。

关于更多的逻辑分组、特殊构造可以查看下表。

re使用方法

compile(pattern, flags=0)

    使用compile()函数编译正则表达式,返回正则表达式对象。

import re

p = re.compile(r'[a-z]+')
print(type(p))
输出结果:  <class '_sre.SRE_Pattern'>

表达式对象的方法和属性
通过compile()函数返回的就是表达式对象

match(self, string, pos=0, endpos=-1)
    在string字符串开始位置匹配正则表达式,如果0个或者多个字符被匹配则返回相应的匹配对象,如果不匹配则返回None。

import re
p = re.compile(r'[a-z]+')
print(re.match(p, 'hello'))
#输出结果:<_sre.SRE_Match object; span=(0, 5), match='hello'>
print(re.match(p, '123123'))
#输出结果: None
fullmatch(self, string, pos=0, endpos=-1)
    整个string字符串与该正则表达式对象匹配则返回相应的匹配对象,否则返回None。相当于给正则表达式加上了边界字元字符^$

import re
p = re.compile(r'[a-z]+')
print(re.match(p, 'hello'))
#输出结果: <_sre.SRE_Match object; span=(0, 5), match='hello'>
print(re.match(p, '123123'))
#输出结果: None
search(self, string, pos=0, endpos=-1)
    扫描整个string字符串,查找正则表达式对象可以匹配的子串第一次出现的位置,并返回相应的匹配对象,如果没有匹配的内容则返回None。
search()在字符串的任意位置进行匹配检测;match仅在字符串开始位置进行匹配检测。

import re
f = 'abcdefg' print(re.search(r'^c', f))
#输出结果: None print(re.search(r'^a', f))
#输出结果:<_sre.SRE_Match object; span=(0, 1), match='a'>
findall(self, string, pos=0, endpos=-1)
    搜索string字符串中与正则表达式匹配的所有子串,以列表形式返回。

import re
test = "He was carefully disguised but captured quickly by police." ##查找以ly结尾的单词 print(re.findall(r'\w+ly', test))   
#输出结果:  ['carefully', 'quickly']
finditer(self, string, pos=0, endpos=-1)

    搜索string字符串中与正则表达式匹配的所有子串,以迭代器形式返回。

import re
test = "He was carefully disguised but captured quickly by police."  for i in re.finditer(r'\w+ly', test):
    print("{0}-{1}:{2}".format(i.start(), i.end(), i.group()))
#输出结果: 7-16:carefully
40-47:quickly
sub(self, repl, string, count=0)
替换string字符串中与正则表达式匹配的count个子串,返回替换修改后的字符串。

import re

test = "pro--gr-am" print(re.sub(r'-+', '', test))
#输出结果: program
split(self, string, maxsplit=0)
以正则表达式匹配的字符串为分隔符,对一个字符串进行分割,以列表形式返回分隔后的各个字符串。

import re

test = "Words, words, words." print(re.split(r'\W+', test))  #非字母和数字 作为 分隔符 #输出结果: ['Words', 'words', 'words', '']
上述方法中部分参数说明
string  要匹配或处理的字符串
pos  表示从string字符串的哪个位置开始
endpos  表示到string字符串的哪个位置结束
maxsplit  表示最大切割次数,默认值0,表示能切割多少次就尽可能多的切割多少次


匹配对象的方法
用正则表达式对象的regex.match()、regex.fullmatch()和regex.search()得到的结果就是一个匹配对象

  • group(self, *args)
    返回一个或多个指定捕获组匹配到的内容。若只有一个参数则返回值是一个单独的字符串;若有多个参数则返回值是包含每一个指定分组所对应的匹配字符串的元组;若不指定参数,则group1默认为0,将返回整个正则表达式所匹配的内容。
  • groups(self, default=None)
    返回一个包含所有分组所匹配内容的元组,如果某个分组没有匹配的内容,则取default所指定的值。
  • groupdict(self, default=None)
    返回一个包含所有命名分组名称及其所匹配内容的字典对象,如果某个分组没有匹配的内容,则取default所指定的值。
  • start()
    返回匹配到内容的开始位置。
  • end()
    返回匹配到内容的结束位置。
  • span()
    返回包含匹配到内容开始和结束位置的元组(start, end)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    >>> import re
    >>> p = re.compile(r'.*name\s+is\s+(\w+).*am\s+(?P<age>\d{1,3})\s+years.*tel\s+is\s+(?P<tel>\d{11}).*', re.DOTALL)
    >>> string = '''
    ... My name is Tom,
    ... I am 16 years old,
    ... My tel is 13972773480.
    ... '''
    >>> m = p.match(string)
    >>> print(m.group())
    
    My name is Tom,
    I am 16 years old,
    My tel is 13972773480.
    
    >>> print(m.group(0))
    
    My name is Tom,
    I am 16 years old,
    My tel is 13972773480.
    
    >>> print(m.group(1))
    Tom
    >>> print(m.group(2))
    16
    >>> print(m.group(3))
    13972773480
    >>> print(m.group('tel'))
    13972773480
    >>> print(m.groups())
    ('Tom', '16', '13972773480')
    >>> print(m.groupdict())
    {'age': '16', 'tel': '13972773480'}
    

re在模块级别提供的函数如下

1
2
3
4
5
6
match(pattern, string, flags=0)
fullmatch(pattern, string, flags=0)
search(pattern, string, flags=0)
findall(pattern, string, flags=0)
sub(pattern, repl, string, count=0, flags=0)
split(pattern, string, maxsplit=0, flags=0)

函数名称和re对象所提供的函数名称同名,其实就是正则表达式对象方法的封装,功能相同。
通过complie()声明正则对象,然后调用正则对象方法效率比直接使用模块级别函数高。

  • 正则表达式的r前缀
    对于一些特殊的字符需要通过/(反斜线)进行转义处理才能被正确的识别。加上r(raw,原始的意思)表示字符串的字面值就是其真实值,不需要进行转义等操作。

关于python正则语法,可以点击Regular Expression HOWTO查看更多内容。

关于python正则模块使用,可以点击 Regular expression operations查看更多内容。


 数量词的贪婪模式与非贪婪模式

    正则表达式通常用于在文本中查找匹配的字符串。

    Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"。