正则表达式工具 |
grep |
语言和函数库 |
Boost |
Delphi |
GNU (Linux) |
Groovy |
Java |
JavaScript |
.NET |
PCRE (C/C++) |
PCRE2 (C/C++) |
Perl |
PHP |
POSIX |
PowerShell |
Python |
R |
Ruby |
std::regex |
Tcl |
VBScript |
Visual Basic 6 |
wxWidgets |
XML Schema |
Xojo |
XQuery 和 XPath |
XRegExp |
数据库 |
MySQL |
Oracle |
PostgreSQL |
此网站的更多信息 |
简介 |
正则表达式快速入门 |
正则表达式教程 |
替换字符串教程 |
应用程序和语言 |
正则表达式范例 |
正则表达式参考 |
替换字符串参考 |
Python 的 re 模块
Python 是一种高端开源脚本语言。Python 内置的「re」模块提供优异的 正则表达式 支持,具备现代且完整的正则表达式风格。Python 3.11 添加了两个重要的遗失功能,原子组 和 独占量词。虽然 Python 的正则表达式引擎可以正确处理 Unicode 字符串,但其语法仍缺少 Unicode 属性,而 简写字符类别 也只会比对 ASCII 字符。
首先,使用 import re
将 regexp 模块导入您的脚本。
正则表达式搜索和比对
调用 re.search(regex, subject)
以将正则表达式样式套用至主旨字符串。如果比对尝试失败,函数会传回 None
,否则会传回 Match
对象。由于 None
会评估为 False
,因此您可以在 if
陈述式中轻松使用 re.search()
。 Match
对象会保存正则表达式样式比对到的字符串部分的详细数据。
您可以通过将特殊常数指定为 re.search()
的第三个参数,来设置 正则表达式比对模式。 re.I
或 re.IGNORECASE
会不区分大小写地套用样式。 re.S
或 re.DOTALL
会让 点号比对换行符号。 re.M
或 re.MULTILINE
会让 插入符号和美元符号 在主旨字符串中比对换行符号前后。单字母选项和描述性选项之间没有差异,除了您必须输入的字符数。若要指定多个选项,请使用 | 算子将它们「或」起来:re.search("^a", "abc", re.I | re.M)
。
缺省情况下,Python 的正则表达式引擎只将字母 A 到 Z、数字 0 到 9 以及底线视为「字符字符」。指定旗标 re.L
或 re.LOCALE
以使 \w
比对所有根据目前区域设置视为字母的字符。或者,您可以指定 re.U
或 re.UNICODE
以将所有字符的字母视为字符字符。此设置也会影响 字符边界。
不要将 re.search()
与 re.match()
混淆。这两个函数运行完全相同的动作,重要的区别在于 re.search()
会在字符串中尝试比对样式,直到找到符合的结果。另一方面,re.match()
只会在字符串的开头尝试比对样式。基本上,re.match("regex", subject)
与 re.search("\Aregex", subject)
相同。请注意,re.match()
并不要求 正则表达式与整个字符串相符。re.match("a", "ab")
会成功。
Python 3.4 添加一个新的 re.fullmatch()
函数。此函数只有在正则表达式完全与字符串相符时才会传回 Match
对象。否则,它会传回 None
。re.fullmatch("regex", subject)
与 re.search("\Aregex\Z", subject)
相同。这对于验证用户输入很有用。如果 subject
是空字符串,则对于任何可以找到 零长度比对 的正则表达式,fullmatch()
会评估为 True
。
若要从字符串取得所有比对结果,请调用 re.findall(regex, subject)
。这会传回一个数组,其中包含字符串中所有不重叠的正则表达式比对结果。「不重叠」表示字符串从左到右搜索,而下一个比对尝试会从前一个比对结果之后开始。如果正则表达式包含一个或多个 捕获组,re.findall()
会传回一个数组,其中每个数组元素都包含由所有捕获组比对到的文本。整体正则表达式比对结果不会包含在数组元素中,除非您将整个正则表达式置于捕获组中。
比 re.findall()
更有效率的是 re.finditer(regex, subject)
。它会传回一个反复运算器,让您可以在主旨字符串中的正则表达式比对结果中进行循环:for m in re.finditer(regex, subject)
。for 循环变量 m
是 Match
对象,其中包含目前比对结果的详细数据。
与 re.search()
和 re.match()
不同,re.findall()
和 re.finditer()
不支持使用正则表达式比对旗标的第三个选用参数。相反地,您可以在正则表达式的开头使用 全域模式修改器。例如,「(?i)regex」比对 regex
时不区分大小写。
字符串、反斜线和正则表达式
反斜线是正则表达式中的元字符。它用于转义其他元字符。正则表达式 \\
符合单一反斜线。 \d
是单一记号,符合数字。
Python 字符串也使用反斜线来转义字符。上述正则表达式写成 Python 字符串为 "\\\\"
和 "\\d"
。确实令人混淆。
幸运的是,Python 也有「原始字符串」,不会对反斜线套用特殊处理。作为原始字符串,上述正则表达式变成 r"\\"
和 r"\d"
。使用原始字符串的唯一限制是,用于字符串的分隔符号不能出现在正则表达式中,因为原始字符串没有提供转义它的方法。
你可以在原始字符串中使用 \n 和 \t。尽管原始字符串不支持这些转义,但正则表达式引擎支持。最终结果是一样的。
Unicode
在 Python 3.3 之前,Python 的 re 模块不支持任何Unicode 正则表达式记号。然而,Python Unicode 字符串一直支持 \uFFFF
表示法。Python 的 re 模块可以使用 Unicode 字符串。因此,你可以将 Unicode 字符串 u"\u00E0\\d"
传递给 re 模块,以符合 à
后接数字。 \d
的反斜线已转义,而 \u
的反斜线则没有。这是因为 \d
是正则表达式记号,而正则表达式反斜线需要转义。 \u00E0
是不应转义的 Python 字符串记号。正则表达式引擎将字符串 u"\u00E0\\d"
视为 à\d
。
如果你在 \u
前面再放一个反斜线,正则表达式引擎会看到 \u00E0\d
。如果你在 Python 3.2 或更早版本中使用这个正则表达式,它将符合文本 u00E0
后接数字。
为了避免混淆反斜线是否需要转义,请使用 Unicode 原始字符串,例如 ur"\u00E0\d"
。这样反斜线就不需要转义。Python 会在原始字符串中诠释 Unicode 转义。
在 Python 3.0 和更新版本中,字符串缺省为 Unicode。因此,上述范例中显示的 u
前缀不再需要。Python 3.3 也为正则表达式引擎添加支持 \uFFFF
表示法。因此,在 Python 3.3 中,您可以使用字符串 "\\u00E0\\d"
来传递 regex \u00E0\d
,它会比对类似 à0
的字符串。
搜索和取代
re.sub(regex, replacement, subject)
在 subject 中运行搜索和取代,将 subject 中所有 regex 比对结果取代为 replacement。结果由 sub()
函数传回。您传递的 subject 字符串不会被修改。
如果 regex 有 捕获组,您可以使用 regex 中捕获组内部分比对的文本。若要取代第三个群组的文本,请在 replacement 字符串中插入 \3
。如果您想要使用第三个群组的文本,后面加上一个文本三作为取代字符串,请使用 \g<3>3
。 \33
会被解释为第 33 个群组。如果群组少于 33 个,则会发生错误。如果您使用 命名捕获组,则可以在 replacement 文本中使用 \g<name>
。
re.sub()
函数对 replacement 文本套用与正则表达式相同的反斜线逻辑。因此,您应该对 replacement 文本使用原始字符串,就像我在上述范例中所做的那样。 re.sub()
函数也会在原始字符串中解释 \n 和 \t。如果您想要 c:\temp
作为取代字符串,请使用 r"c:\\temp"
或 "c:\\\\temp"
。第三个反向引用是 r"\3"
或 "\\3"
。
分割字符串
re.split(regex, subject)
传回一个字符串数组。数组包含 subject 中所有 regex 比对结果之间的 subject 部分。相邻的 regex 比对结果会导致数组中出现空字符串。regex 比对结果本身不会包含在数组中。如果 regex 包含 捕获组,则捕获组比对的文本会包含在数组中。捕获组会插入在出现在 regex 比对结果左边和右边的子字符串之间。如果您不想要数组中的捕获组,请将它们转换为 非捕获组。 re.split()
函数没有提供抑制捕获组的选项。
您可以指定一个额外的第三个参数来限制分割 subject 字符串的次数。请注意,此限制控制分割的次数,而不是数组中最终会出现的字符串数。未分割的 subject 余数会添加为数组中的最后一个字符串。如果没有捕获组,则数组将包含 limit+1
个项目。
当正则表达式可以找到长度为 0 的比对时,re.split()
的行为在不同版本的 Python 中有所改变。在 Python 3.4 及更早版本中,re.split()
会忽略长度为 0 的比对。在 Python 3.5 和 3.6 中,re.split()
在遇到长度为 0 的比对时会掷出 FutureWarning。这个警告表示 Python 3.7 中的变更。现在 re.split()
也会对长度为 0 的比对进行分割。
比对详细数据
re.search()
和 re.match()
会传回一个比对对象,而 re.finditer()
会产生一个反复器,用于反复处理比对对象。这个对象包含许多关于正则表达式比对的有用信息。以下的讨论中,我将使用 m
来表示比对对象。
m.group()
会传回与整个正则表达式比对的字符串部分。 m.start()
会传回比对开始处在字符串中的偏移量。 m.end()
会传回比对结束后一个字符的偏移量。 m.span()
会传回 m.start()
和 m.end()
的 2 元组。您可以使用 m.start()
和 m.end()
来切片主旨字符串:subject[m.start():m.end()]
。
如果您想要捕获组的结果,而不是整体正则表达式比对,请指定群组的名称或编号作为参数。 m.group(3)
会传回由第三个 捕获组 比对的文本。 m.group('groupname')
会传回由 命名组 'groupname' 比对的文本。如果群组未参与整体比对,m.group()
会传回空字符串,而 m.start()
和 m.end()
会传回 -1。
如果您想要运行基于正则表达式的搜索和取代,而不使用 re.sub()
,请调用 m.expand(replacement)
来计算取代文本。这个函数会传回已取代反向引用等的取代字符串。
正则表达式对象
如果您想要重复使用相同的正则表达式,您应该将其编译成正则表达式对象。正则表达式对象更有效率,并让您的代码更具可读性。若要创建一个,只需调用 re.compile(regex)
或 re.compile(regex, flags)
。flags 是上面针对 re.search()
和 re.match()
函数描述的比对选项。
由 re.compile()
传回的正则表达式对象提供 re 模块也直接提供的全部函数:search()
、match()
、findall()
、finditer()
、sub()
和 split()
。不同之处在于它们使用保存在 regex 对象中的样式,且不将 regex 作为第一个参数。re.compile(regex).search(subject)
等同于 re.search(regex, subject)
。