UP | HOME

Python 正则表达式

目录

1 简介

处理复杂的文本的时候, 使用 正则表达式 能够很大程度上减轻我们的工作量。

这篇博客的主要内容是针对 Python 的正则表达式模块 re 的理解和使用, 有关正则表达式语法的内容可以查看 正则表达式.

本篇博客未列举出来的内容可查阅 官方文档 进行了解.

2 模块和对象

为了更好的理解 re 模块的使用, 我们首先将 re 模块涉及到的 三个对象 列举出来:

  • 模块对象: 模块对象指的就是 re 模块本身。
  • 正则表达式对象: 通常为调用 re.compile 编译正则表达式模式后返回的对象。
  • 正则表达式匹配对象: 通常为调用 re.matchre.search 后返回的对象。

三个对象 列举出来的原因是需要 分清楚 我们调用的 方法函数 到底是属于那一个对象。

我就在错误的对象身上调用过的正确的方法并得到了合适一个异常。

首先, 模块对象正则表达式对象 的方法基本相同, 一定程度上, 模块对象 的是对 正则表达式对象 的一层封装。

然后, 正则表达式匹配对象 的对象和另外两者的区别很大, 使用的时候需要分清楚。

3 模块对象和正则表达式对象

由于 模块对象正则表达式 对象的使用十分接近, 就把两者的内容放在一起了。

re.compile(pattern, flags=0)

这个方法只适用于 模块对象, 使用任何可选的 flag 来编译正则表达式模式,并返回一个 正则表达式对象.

多个标记可以通过按位或操作符 | 合并.

详细的 flags 可以参考官方文档: Module Contents

match(pattern, string, flags=0)

尝试从字符串的 起始部分 对模式进行匹配, 如果匹配成功就返回一个 匹配对象, 匹配失败返回 None.

注意: 是从起始部分进行匹配。

search(pattern, string, flags=0)

这个方法的工作方式和 match 基本相同, 不同之处在于 search 会在字符串的 任意位置 尝试对模式进行匹配。 匹配成功返回 匹配对象, 匹配失败返回 None.

注意: 是任意位置进行匹配。

findall(pattern, string, [,flags])

这个方法查找字符串中 所有 非重复出现的正则表达式模式, 并返回一个列表。 如果没有匹配到的话就返回一个 空的 列表。

需要注意的一种情况是匹配模式的 分组多于 1 的时候的匹配结果:

In [2]: re.findall(r'\w+', 're: Regular expression operations')
Out[2]: ['re', 'Regular', 'expression', 'operations']

In [3]: re.findall(r'(\w+)', 're: Regular expression operations')
Out[3]: ['re', 'Regular', 'expression', 'operations']

In [5]: re.findall(r'(\w+).(\w+)', 're: Regular expression operations')
Out[5]: [('Regular', 'expression'), ('operatio', 's')]

上面三个语句分别对应分组为 0, 1, 2 时的执行情况.

分组为 01 时, 返回的 列表 中的元素都是匹配的 字符串.

当分组为 2 时, 返回的 列表 中的元素就变为了 元组.

元组 内的元素的顺序对应每个 的匹配结果。

In [6]: re.findall(r'(\w+(\w))', 're: Regular expression operations')
Out[6]: [('re', 'e'), ('Regular', 'r'), ('expression', 'n'), ('operations', 's')]

对于匹配模式 (\w+(\w)) 来说, (\w+(\w)) 是分组 1, 而 (\w) 是分组 2.

finditer(pattern, string, [,flags])
findall 相同, 只不过返回的是一个 迭代器, 而不是 列表.
split(pattern, string, max=0)

参考 sstr.split, 作用是类似的。 只不过分割字符串的参考依据由单个字符变为了 匹配模式.

可以通过 max 指定最大分割次数:

In [13]: re.split(r'\w\s\w', 'Hello World !')
Out[13]: ['Hell', 'orld !']
sub(pattern, repl, string, count=0)

使用 repl 替换 string 中出现的和 pattern 相匹配的字符串, 通过 count 指定替换次数, 默认为替换所有。

注: repl 中可以使用 回溯引用.

In [18]: re.sub(r'\w+?(T)\w', r'\1', 'asdTgdfTdgfhTdsfgTf')
Out[18]: 'TTTT'

PS: 如无特殊说明, 那么该方法同时适用于 模块对象正则表达式对象.

4 正则表达式匹配对象

匹配对象 通常为 re.matchre.search 返回的对象。

在涉及 匹配对象 的方法之前, 需要了解的一个东西是 正则表达式的分组.

通常, 我们可以在 匹配模式 中使用 () 来定义 元组(子组). 这些 元组 会根据定义的顺序被设置一个 编号.

这个 编号 被用来代表那个 分组, 正则表达式中的 回溯引用 等也会用到那个编号。

首先, 最基本的一点是: 整个匹配模式的编号是 0.

对于剩下的分组, 可以通过网站 JavaScript Regular Expression Visualizer. 进行可视化分析.

虽然是 JavaScript 的正则表达式, 但是道理是通的.

比如: ^(\w+)\s+(\w{3}(\w{2}))+$ 的分组可以表示为:

group.png

明白了分组的概念, 再来理解 匹配对象 的方法就容易很多了:

group(num=0)
返回整个匹配对象或编号为 num 的特定子组
groups(default=None)
返回一个包含所有匹配子组的元组
groupdict(default=None)
返回一个包含所有匹配的 命名子组 (Python 语法扩展) 的字典,所有的子组名作为字典的键。

需要注意的是, 如果 re.matchre.search 的匹配不成功, 那么返回的结果就是 None, 而不是 匹配对象.

5 语法扩展和原始字符串

Python 对正则表达式的语法做了一些扩展:

扩展表示法 作用 例子
(?iLmsux) 放在匹配模式的 开头, 相当于 flags 参数 (?i)\w+ 不区分大小写
(?:...) 表示一个匹配 不用保存 的分组 (?:\w+)
(?P<name>...) 定义一个 命名分组 (?P<word>\w+)
(?P=name) 命名分组的 回溯引用 (P=word)
(?#...) 注释 (?#comment)

适当程度上的使用 扩展语法 可以节约一定的工作量。

原始字符串:

在正则表达式中, \ 是转义字符。

Python 中, \ 也是转义字符。

这时, 如果不使用原始字符串, 那么匹配模式中的 \ 就需要写为 \\.

如果要匹配 \, 那么匹配模式就成了 \\\\.

这样十分影响匹配模式的阅读理解, 还容易出错。

此时, 使用原始字符串解决这一问题:

r'string'  # 在字符串前面加上 r 即可

6 参考链接

版权声明:本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可