Menu

Python 正则表达式教程:re 模块、模式、分组与替换

动手学习 Python 的 re 模块:搜索、匹配、捕获分组、替换,以及你最常用到的模式。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

什么时候该用正则表达式

正则表达式是一种用来描述文本模式的小型语言。它很强大,也很容易被滥用。

在动用 re 之前,先想想普通的字符串方法能不能搞定。.split()、.replace()、.startswith()、"target" in text 比等价的正则表达式更快、更易读,也更不容易出错。把正则表达式留给那些确实有规律、但对固定的字符串操作来说又太灵活的模式:电子邮件地址、电话号码、格式已知的日志行、HTML 或 Markdown 片段,以及任何“找出这类东西”的搜索。

基本词汇

正则表达式模式是一个描述你要找什么的字符串。几个基本构件:

  • .:任意单个字符
  • \d:任意数字(0 到 9)
  • \w:任意“单词”字符(字母、数字、下划线)
  • \s:任意空白字符
  • ^:字符串开头
  • $:字符串结尾
  • [abc]:a、b、c 中的任意一个
  • [^abc]:除 a、b、c 之外的任意字符
  • a|b:a 或 b
  • *:前一个元素出现零次或多次
  • +:一次或多次
  • ?:零次或一次
  • {3}:正好 3 次
  • {2,5}:2 到 5 次
  • ( ... ):分组(捕获其中匹配的内容)

这些足以应付大多数实际场景中的正则表达式。

主要函数

re.search(pattern, text) 在字符串的任意位置查找第一个匹配。返回一个匹配对象或 None:

正则表达式模式请始终使用原始字符串(r"...")。否则 Python 会尝试把反斜杠解释为字符串转义,你得到的模式就和你输入的不一样了。

re.match(pattern, text) 和 search 类似,但只在开头匹配:

大多数时候你需要的是 search。

re.findall(pattern, text) 以列表形式返回所有不重叠的匹配:

注意,findall 返回的是字符串,而不是匹配对象。如果模式中有一个分组,你得到的是分组的内容。如果有多个分组,你得到的是一个元组列表。

捕获分组

模式中的圆括号会捕获其中匹配到的内容:

命名分组通常更清楚:

一旦正则表达式有不止一个分组,给它们命名会让提取数据的代码好懂得多。

用 re.sub 替换

re.sub(pattern, replacement, text) 会替换所有匹配:

这会去掉所有不是数字的字符。替换字符串可以用 \1、\2 等引用捕获的分组;在原始字符串中,\g<1> 的写法更清楚:

你也可以传入一个函数作为替换内容。对于不是简单交换的转换,这很有用:

编译模式以便复用

如果你要多次使用同一个模式(尤其是在循环中),就先编译一次:

编译后的模式提供同样的方法:search、match、findall、sub,只是不需要再把模式作为第一个参数。效率稍高一些,通常也更易读。

标志

常用的修饰符,可以通过 flags= 参数传入,或者用“或”运算组合在一起:

  • re.IGNORECASE(re.I):不区分大小写的匹配。
  • re.MULTILINE(re.M):^ 和 $ 在每一行都能匹配,而不只是字符串的边界。
  • re.DOTALL(re.S):. 也能匹配换行符(默认不能)。
  • re.VERBOSE(re.X):允许在模式中使用空白和 # 注释,提高可读性。

re.VERBOSE 对复杂的模式尤其有用:

分多行写、带注释的正则表达式,比晦涩的单行写法好维护得多。

贪婪与非贪婪

量词(*、+、?、{n,})默认是贪婪的:它们会尽可能多地匹配。加上一个 ? 就能让它们变成非贪婪(惰性)的:

贪婪版本捕获了从 <b> 到 </i> 的整段子串,这多半不是你想要的。非贪婪的 .+? 会在第一个 > 处停下。

(顺便提一句:在生产环境中,不要真的用正则表达式解析 HTML。请使用 html.parser 或 BeautifulSoup。上面的例子只是为了演示贪婪匹配。)

一个贴近实际的例子

解析一种简单日志格式中的行:

没几行代码,却能做很多事。

几个好习惯

  • 模式始终使用原始字符串。
  • 先写能用的最简单的模式,之后再收紧。
  • 分组不止一个时,使用命名分组。
  • 要复用的模式先编译。
  • 正则表达式比普通的字符串方法慢。如果 .split() 就能搞定,那就用 .split()。

下一步:错误与调试

到这里,处理真实数据的内容就讲完了:文件、JSON、CSV、HTTP、日期和正则表达式。不过,任何真实的程序迟早都会遇到错误,而读懂 Python 的 traceback 是你能学到的最重要的调试技能。最后一章介绍异常,以及你最常遇到的那些具体错误。

常见问题

Python 中的正则表达式是什么?

正则表达式(regex)是一种用来描述文本模式的小型语言。Python 的 re 模块让你可以搜索模式、提取片段和替换匹配的内容。对于简单的字符串操作来说,它有点大材小用,应该先用 .split() 或 .replace() 这样的字符串方法;但在有规律的模式匹配上,它无可替代。

re.match 和 re.search 有什么区别?

re.match 只在字符串的开头进行匹配。re.search 会扫描整个字符串,找到任意位置的第一个匹配。拿不准的时候就用 search,它更符合人的直觉。

正则表达式模式应该总是用原始字符串吗?

是的。正则表达式模式里经常有反斜杠(\d、\s、\b),而 Python 字符串会把它们解释为转义序列。在前面加上 r,写成 r'\d+',就是告诉 Python 按字面意思处理这个字符串,这样正则表达式本身也更易读。

Coddy 编程语言插图

和 Coddy 一起学编程

开始