Python正则表达式


纸上得来终觉浅,绝知此事要躬行。

Pythonre 模块提供各种正则表达式的匹配操作,和 Perl 脚本的正则表达式功能类似,使用这一内嵌于 Python 的语言工具,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。Python 会将正则表达式转化为字节码,利用 C 语言的匹配引擎进行深度优先的匹配。

Python正则表达式


1. 正则匹配方式

  • match
    • 匹配格式:re.match(pattern, string, flags=0)
    • 使用说明:从给定字符串的首字母开始逐个匹配
In [2]: re.match('test', 'test')
Out[2]: <_sre.SRE_Match object; span=(0, 4), match='test'>

In [3]: re.match('test', 'atest')
  • search
    • 匹配格式:re.search(pattern, string, flags=0)
    • 使用说明:从给定字符串中任意位置开始匹配
In [4]: re.search('test', 'atest')
Out[4]: <_sre.SRE_Match object; span=(1, 5), match='test'>

In [5]: re.search('test', 'test123')
Out[5]: <_sre.SRE_Match object; span=(0, 4), match='test'>

In [6]: re.search('test', 'test')
Out[6]: <_sre.SRE_Match object; span=(0, 4), match='test'>
  • compile
    • 匹配格式:re.compile(r'xxx', flags=0)
    • 使用说明:编译正则表达式是为了加速执行效率
# re.compile('pattern', re.I|re.M)与re.compile('(?im)pattern')是等价
In [37]: regex = re.compile(r'^\d{1,3}$')

In [38]: regex.match('12')
Out[38]: <_sre.SRE_Match object; span=(0, 2), match='12'>

In [39]: regex.search('12')
Out[39]: <_sre.SRE_Match object; span=(0, 2), match='12'>

# 编译时用的表达式字符串
In [42]: regex.pattern
Out[42]: '^\\d{1,3}$'

# 编译时用的匹配模式,数字形式呈现
In [43]: regex.flags
Out[43]: 32

# 表达式中分组的数量
In [44]: regex.groups
Out[44]: 0

# 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内
In [45]: regex.groupindex
Out[45]: mappingproxy({})
  • 编译标志
语法 说明
re.I re.IGNORECASE;忽略字母大小写
re.M re.MULTILINE;多行模式,改变'^''$'的行为
re.S re.DOTALL;使用.匹配包括换行在内的所有字符
re.L re.LOCALE;使预定字符类\w \W \b \B \s \S取决于当前区域设定
re.U re.UNICODE;使预定字符类\w \W \b \B \s \S \d \D取决于 unicode 定义的字符属性
re.X re.VERBOSE;详细模式,该模式下正则表达式可以是多行,忽略空白字符且可以加入注释
In [34]: re.search('.', '\n')

In [35]: re.search('.', '\n', re.S)
Out[35]: <_sre.SRE_Match object; span=(0, 1), match='\n'>

In [36]: re.search('a.', 'A\n', re.S|re.I)
Out[36]: <_sre.SRE_Match object; span=(0, 2), match='A\n'>

2. 正则匹配符号

  • 重复元字符
语法 说明
. 小圆点符号表示匹配除换行符以外的任意字符
? 匹配前面的子表达式零次或一次
+ 匹配前面的子表达式一次或多次
* 匹配前面的子表达式零次或多次
x/y 匹配 x 或 y 其中的一个字符即可
[xyz] 字符集合,匹配所包含的任意一个字符
[a-z] 字符范围,匹配指定范围内的任意字符
[^x] 匹配除了 x 以外的任意字符
[^abc] 匹配除了 abc 这几个字母以外的任意字符
{m} 重复前面的子表达式 m 次
{m,} 重复前面子表达式 m 次或者更多次
{m,n} 重复前面的子表达式至少 m 次至多 n 次
In [8]: re.search('\d{5}', '123456')
Out[8]: <_sre.SRE_Match object; span=(0, 5), match='12345'>

In [9]: re.search('ca*t', 'catzzz')
Out[9]: <_sre.SRE_Match object; span=(0, 3), match='cat'>

In [10]: re.search('catz{1,2}', 'catzzz')
Out[10]: <_sre.SRE_Match object; span=(0, 5), match='catzz'>
In [12]: re.search('..', 'cat')
Out[12]: <_sre.SRE_Match object; span=(0, 2), match='ca'>

In [14]: re.search('a|e', 'abcd')
Out[14]: <_sre.SRE_Match object; span=(0, 1), match='a'>

In [15]: re.search('[a12]', 'abcd')
Out[15]: <_sre.SRE_Match object; span=(0, 1), match='a'>

In [16]: re.search('[a-z]', 'abc')
Out[16]: <_sre.SRE_Match object; span=(0, 1), match='a'>
  • 预定义元字符
语法 说明
\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_]
In [17]: re.search('..', 'hi')
Out[17]: <_sre.SRE_Match object; span=(0, 2), match='hi'>

In [18]: re.search('\w\w\w\w', 'a1_哈')
Out[18]: <_sre.SRE_Match object; span=(0, 4), match='a1_哈'>

In [19]: re.search('\s\s\s', ' \t\r')
Out[19]: <_sre.SRE_Match object; span=(0, 3), match=' \t\r'>

In [20]: re.search('\d\d', '12')
Out[20]: <_sre.SRE_Match object; span=(0, 2), match='12'>
  • 边界匹配元字符
语法 说明
^ 匹配字符串的开始
$ 匹配字符串的结束
\A 仅匹配字符串开头
\Z 仅匹配字符串结尾
\b 匹配单词的开始或结束元字符
\B 匹配非单词的开始或结束元字符
In [21]: re.search('^test', 'test123')
Out[21]: <_sre.SRE_Match object; span=(0, 4), match='test'>

In [22]: re.search('^test', '123test123')

In [23]: re.search('123$', 'test123')
Out[23]: <_sre.SRE_Match object; span=(4, 7), match='123'>

In [24]: re.search('123$', 'test123t')

3. 正则惰性匹配

  • 贪婪限定符
语法 说明
? 匹配前面的子表达式零次或一次
+ 匹配前面的子表达式一次或多次
* 匹配前面的子表达式零次或多次
{n,} 重复 n 次或更多次
{n,m} 重复 n 到 m 次
  • 惰性限定符
语法 说明
? 重复任意次,但尽可能少重复
+? 重复 1 次或更多次,但尽可能少重复
?? 重复 0 次或 1 次,但尽可能少重复
{n,}? 重复 n 次以上,但尽可能少重复
{n,m}? 重复 n 到 m 次,但尽可能少重复
In [30]: re.search('a.*b', 'aabab')
Out[30]: <_sre.SRE_Match object; span=(0, 5), match='aabab'>

In [31]: re.search('a.*b', 'aabab').group()
Out[31]: 'aabab'

In [32]: re.search('a.*?b', 'aabab')
Out[32]: <_sre.SRE_Match object; span=(0, 3), match='aab'>

In [33]: re.search('a.*?b', 'aabab').group()
Out[33]: 'aab'

4. 正则匹配内容

语法 说明 表达式实例
/ 表示左右表达式匹配任意一个,总是从左到右匹配 -
(...) 被括起来的表达式将作为分组,从表达式左边开始每遇到一个分组的左括号,编号递增1 -
<number> 引用编号为<number>的分组匹配到的字符串 (\d)abc\1表示可以匹配到1abc1/2abc2
(?P<name>...) 分组,除了原有的编号外再制定一个额外的别名 (?P<name>escape)表示只能匹配到escapename是起的别名,可以在后续使用到
(?P=name) 引用别名为<name>的分组匹配到的字符串 (?P<id>\d)abc(?P=id)表示可以匹配到1abc1/2abc2
  • 检索内容
In [46]: re.findall('\d', '1a2b3c4d')
Out[46]: ['1', '2', '3', '4']

In [47]: for i in re.finditer('\d', '1a2b3c4d'):
    ...:     print(i)
    ...:
<_sre.SRE_Match object; span=(0, 1), match='1'>
<_sre.SRE_Match object; span=(2, 3), match='2'>
<_sre.SRE_Match object; span=(4, 5), match='3'>
<_sre.SRE_Match object; span=(6, 7), match='4'>
  • 内容分组
In [48]: m = re.match('(a)b', 'ab')

In [49]: m.group(1)
Out[49]: 'a'

In [50]: m = re.match('([a-c]+).*(\w)', 'abcbde')

In [51]: m.groups()
Out[51]: ('abcb', 'e')

In [52]: m.group(1), m.group(2), m.group(1, 2)
Out[52]: ('abcb', 'e', ('abcb', 'e'))
  • 命名分组
In [53]: pattern = '(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'

In [54]: m = re.match(pattern, '2018-06-23')

In [55]: m.groupdict()
Out[55]: {'day': '23', 'month': '06', 'year': '2018'}

In [56]: m.group('year')
Out[56]: '2018'

In [57]: m.groups()
Out[57]: ('2018', '06', '23')

5. 正则高阶函数

正则表达式中提供了一些高阶函数用于提到匹配的效率和使用的方便

5.1 split 函数

  • 格式说明
    • split(string[, maxsplit])
    • re.split(pattern, string[, maxsplit])
  • 使用说明
    • 按照能够匹配的子串将string分割后返回列表
    • 如果在模式中使用捕获括号,则模式中所有组的文本也作为生成列表的一部分返回
    • 参数maxsplit用于指定最大分割次数,不指定将全部分割
    • 参数maxsplit不为零,则最多会出现maxsplit拆分,并将该字符串的其余部分作为列表的最后一个元素返回
### input ###
p = re.compile(r'\d+')
print(p.split('one1two2three3four'))

### output ###
# ['one', 'two', 'three', 'four']
>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']

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

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

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

>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']

5.2 findall 函数

  • 格式说明
    • findall(string[, pos[, endpos]])
    • re.findall(pattern, string[, flags])
  • 使用说明
    • 搜索string,以列表形式返回全部能匹配的子串
### input ###
p = re.compile(r'\d+')
print(p.findall('one1two2three3four4'))

### output ###
# ['1', '2', '3', '4']

5.3 finditer 函数

  • 格式说明
    • finditer(string[, pos[, endpos]])
    • re.finditer(pattern, string[, flags])
  • 使用说明
    • 搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器
### input ###
p = re.compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
    print(m.group()),

### output ###
# 1 2 3 4

3.4 sub 函数

  • 格式说明
    • sub(repl, string[, count])
    • re.sub(pattern, repl, string[, count])
  • 使用说明
    • 使用repl替换string中每一个匹配的子串后返回替换后的字符串
    • repl是一个字符串时,可以使用\id\g<id>\g<name>引用分组,但不能使用编号0
    • repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)
    • 参数count用于指定最多替换次数,不指定时全部替换
### input ###
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print(p.sub(r'\2 \1', s))

def func(m):
    return m.group(1).title() + ' ' + m.group(2).title()
print(p.sub(func, s))

### output ###
# say i, world hello!
# I Say, Hello World!

3.5 subn 函数

  • 格式说明
    • subn(repl, string[, count])
    • re.sub(pattern, repl, string[, count])
  • 使用说明
    • 返回(sub(repl, string[, count]), 替换次数)
    • 多返回一个替换次数的数值,如实例中的数值2
### input ###
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print(p.subn(r'\2 \1', s))

def func(m):
    return m.group(1).title() + ' ' + m.group(2).title()
print(p.subn(func, s))

### output ###
# ('say i, world hello!', 2)
# ('I Say, Hello World!', 2)

3.6 fullmatch 函数

  • 格式说明
    • re.fullmatch
  • 使用说明
    • 如果一个字符串全部匹配才会返回匹配对象,否则返回None
    • 请注意,这与零长度匹配不同
    • Python 3.4引入的函数
>>> pattern = re.compile("o[gh]")

# No match as "o" is not at the start of "dog".
>>> pattern.fullmatch("dog")

# No match as not the full string matches.
>>> pattern.fullmatch("ogre")

# Matches within given limits.
>>> pattern.fullmatch("doggie", 1, 3)
<_sre.SRE_Match object; span=(1, 3), match='og'>

3.7 purge 函数

  • 格式说明
    • re.purge()
  • 使用说明
    • 清除正则表达式缓存
re.purge()

文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !
  目录