Regex 字符”$”并不一定表示 “字符串结尾”

本文讲述的是我最近在为 CPython 开发 SBOM 工具时,使用 Python 的 regex 模块 (re) 发现的一些令人惊讶的行为。

以前使用过正则表达式的人可能知道 ^ 的意思是 “字符串的起始端”,相应地,$ 的意思是 “字符串的结束端”。因此,模式 cat$ 可以匹配字符串 “lolcat”,但不能匹配 “internet cat video”。

^ 的行为让我觉得 $ 也与之类似,但它们并不总是对称的,其行为也与平台有关。特别是对于禁用了多行模式的 Python,$ 字符既可以匹配字符串的结尾,也可以匹配字符串结尾前的换行符。

因此,如果要匹配一个结尾没有换行的字符串,在 Python 中就不能只使用 $!我本以为禁用多行模式就不会出现这种换行匹配行为,但事实并非如此。

下一个合乎逻辑的问题是,在 Python 中如何匹配没有换行的字符串结尾?

在对 Python其他正则表达式语法做了更多研究后,我还发现 \z \Z 可以作为 “字符串结尾 “字符。

在 Python 中使用 re.MULTILINE 可以启用多行模式,文档中有如下说明:

指定 re.MULTILINE 时,模式字符”$“会在字符串末尾和每行末尾(紧接着每个换行符之前)匹配。默认情况下,”$“只与字符串末尾和字符串末尾换行符(如果有)前的字符匹配。

让我们看看这些功能如何在多个平台上协同工作:

Pattern matches "cat\n"? "cat$" multiline "cat$" no multiline "cat\z" "cat\Z"
PHP
ECMAScript ⚠️ ⚠️
Python ⚠️
Golang ⚠️
Java 8
.NET 7.0
Rust ⚠️
  • ✅: 模式匹配字符串 "cat\n"
  • ❌: 模式不匹配字符串 "cat\n"
  • ⚠️: 模式无效或非法字符

综合上表,如果匹配尾部换行是可以接受的,那么使用多行模式的 $ 就可以在所有平台上一致运行,但如果我们不想匹配尾部换行,事情就变得复杂了。

要不匹配尾部换行,可以在所有平台上使用 \z,但 Python 和 ECMAScript 除外,在这两种平台上分别需要使用 \Z 或不带多行模式的 $。希望你今天学到了一些关于正则表达式的知识!

注:数据表来自 regex101.com,我没有使用实际运行时进行测试。

本文文字及图片出自 Regex character “$” doesn't mean “end-of-string”

阅读余下内容
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号