RegExp v flag with set notation + properties of strings S4
中文标题:带有集合表示法和字符串属性的 RegExp
v标志
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2024
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案为 ECMAScript 正则表达式添加了一个新的 v 标志,支持集合表示法,如差集(A--B)、交集(A&&B)和嵌套字符类,以及字符类中的字符串属性和字符串字面量。它解决了对表现力丰富的字符类组合和 Unicode 字符串属性的需求,改进了现有 u 标志的有限语法和不区分大小写匹配。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
ECMAScript 提案:带有集合表示法和字符串属性的 RegExp v 标志
作者
- Markus Scherer
- Mathias Bynens
状态
该提案在 2023 年 5 月 16 日的会议中达到了 TC39 流程 的第 4 阶段。它于 2023 年 6 月 15 日被 合并 到 ECMAScript 规范 中,有望纳入 ECMAScript 2024 快照。
截至 2021 年 5 月 25 日的 TC39 会议,该提案正式包含了 字符串属性提案。
摘要
在 ECMAScript 正则表达式字符类中,我们提议添加以下集合运算的语法和语义:
- 差集/减法(在 A 中但不在 B 中)
- 交集(同时在 A 和 B 中)
- 嵌套字符类(为实现上述功能所必需)
此外,通过与 字符串属性提案 的合并,我们还提议添加某些 Unicode 字符串属性,以及字符类中的字符串字面量。
面向 JavaScript 开发者的提案解释,请参见 我们在 v8.dev 上的特性文章。
动机
许多正则表达式引擎支持命名属性字符,主要反映 Unicode 字符属性,以避免硬编码可能需要数百个范围且可能随 Unicode 新版本变化的字符类。
然而,一个字符属性往往只是起点。常见的需求包括添加(并集)、排除(差集)和“同时满足此和彼”(交集)。参见 UTS #18:Unicode 正则表达式 中支持集合运算的建议。
ECMAScript 正则表达式模式已经以有限形式支持一种集合运算:可以创建字符、范围和类的并集,只要这些类是像 \s 或 \p{Decimal_Number} 这样的 CharacterClassEscape。
在网络上搜索有关此类集合运算的正则表达式问题,会发现一些变通方法,例如硬编码集合运算产生的范围(失去命名属性的好处)和先行断言(对此目的不直观且性能较差)。
我们提议添加差集和交集以及嵌套字符类的语法和语义。
拟议解决方案
我们提议扩展字符类的语法,以支持集合差集/减法、集合交集和嵌套字符类。
高层 API
在正则表达式模式中,我们提议启用以下功能。
在这些高层示例中,A 和 B 可以看作是字符类(例如 [a-z])或属性转义(例如 \p{ASCII})的占位符,可能(取决于具体讨论)是单字符和/或字符范围。参见 说明性示例部分 中的具体实际用例。
说明性示例
来自使用 ICU UnicodeSet 的代码的实际示例,它实现了类似于正则表达式字符类的模式语法(此处修改为使用 \p{Perl syntax for properties} 而不是 [:POSIX syntax for properties:] — UnicodeSet 两者都支持):
-
查找非 ASCII 数字以将其转换为 ASCII 数字:
-
查找特定文字的“单词/标识符字母”范围:
-
查找“分隔空格”:
注意,ECMAScript 目前不支持
\p{Line_Break=…}— 这只是一个说明性示例。 -
查找除 ASCII 表情符号之外的 emoji 字符:
-
查找非特定文字的组合标记:
-
查找除 ASCII 空格之外的“不可见字符”:
-
查找每个文字中的“首字母”,从以下开始:
注意,ECMAScript 目前不支持
\p{NFC_Quick_Check=…}— 这只是一个说明性示例。 -
所有既是字母、标记(例如变音符号)或十进制数字的希腊代码点:
-
所有代码点,除了“其他”
General_Category中的代码点,但重新添加控制字符: -
所有已分配的代码点,除了分隔符:
-
所有从右到左和阿拉伯字母代码点,但移除未分配的代码点:
注意,ECMAScript 目前不支持
\p{Bidi_Class=…}— 这只是一个说明性示例。 -
所有从右到左和阿拉伯字母代码点,且
General_Category为“字母”:注意,ECMAScript 目前不支持
\p{Bidi_Class=…}— 这只是一个说明性示例。 -
General_Category为“其他”的所有字符,除了格式和控制字符(或等效地,所有代理项、私有使用和未分配的代码点):
常见问题解答
新语法是否向后兼容?我们需要另一个正则表达式标志吗?
本提案的一个明确目标是不破坏向后兼容性。具体来说,我们不想改变任何当前不抛出异常的正则表达式模式的行为。需要某种方式来指示正在使用新语法。
我们考虑了 4 个选项:
- 表达式外部的新标志。
- 表达式内部的修饰符,形式为
(?L),其中L是一个 ASCII 字母。(多种正则表达式引擎支持类似的各种修饰符。) - 像
\U…这样的前缀,在当前u标志(Unicode 模式)下无效 — 但注意,没有u标志的\U与U本身相同。- (禁止在
u正则表达式中使用未知转义序列是 一个有意识的选择,以便支持这种扩展。)
- (禁止在
- 像
(?[这样的前缀,在现有模式中不管标志如何都无效。
使用前缀的想法是在早期 TC39 会议上提出的,所以我们一直在研究其变体,例如:
然而,我们发现这不是非常对开发者友好。
特别是,人们必须在 同时 使用 u 标志的情况下编写前缀。Waldemar 指出,前缀 看起来 应该足够了,因此开发者很可能意外地忘记添加 u 标志。虽然这个方面可以通过使用一个更复杂的前缀来解决,该前缀在当前无论是否使用 u 标志都是无效的(如 (?[),但这会牺牲可读性。
此外,使用反斜杠字母前缀会希望将新语法括在 {大括号} 中,因为其他此类语法(\p{property}、\u{12345} 等)使用大括号 — 但对于字符类的最外层不使用 [方括号] 看起来很奇怪。
最后,当一个表达式中有几个新语法字符类时,每个都必须使用前缀,这很笨拙。
表达式内部的修饰符是一个有吸引力的替代方案,但 ECMAScript 尚未使用任何此类修饰符。
因此,新标志是指示新字符类语法的最简单、最用户友好且语法和语义上最干净的方式。它应该 隐含并基于 u 标志。
我们建议使用标志 v,作为 u 之后的字母。
我们还建议 拟议的字符串属性 需要使用这个相同的新标志。
换句话说,新标志将指示几个与属性和字符类相关的连接更改:
- 字符串属性
- 字符类可以包含多字符字符串元素,通过字符串字面量或某些属性
- 嵌套类
- 集合运算符
- 更简单的破折号和方括号解析
- 修复/改进的 IgnoreCase 匹配
更多讨论参见 issue 2。
v 标志与 u 标志有何不同?
这个问题的答案在“升级”现有的 u 正则表达式以使用 v 时会很有用。以下是差异的概述:
-
(这是明显的部分。)以前无效的模式,利用新语法(见上文)现在变得有效,例如
-
一些以前有效的模式现在是错误,特别是那些字符类包含未转义的 特殊字符
()[{}/-|(注意:\和]在字符类内也需要转义,但在u标志下已经是这样了)或 双重标点符号 的模式: -
u标志存在令人困惑的不区分大小写匹配行为。v标志具有不同的、改进的语义。参见 解释器 了解概述,或 issue #30 了解更多详情。
在其他正则表达式风格中有什么先例?
其他几种正则表达式引擎以某种形式支持所提议的部分或全部扩展:
* 差集被 记录 为带否定的交集。仅支持否定 + 嵌套类,你已经有了交集和差集的功能等价物:[^[^ab][^cd]] === [[ab]&&[cd]] 和 [^[^ab][cd]] === [[ab]--[cd]]。这只是不够可读。因此,我们的提案包括专门用于交集和差集的语法。
这些在语法和语义(例如运算符优先级)上都有所不同。参考资料:
一些 Stack Overflow 讨论:
这与 属性字符串即序列属性提案 如何交互?
我们在通往阶段 2 的道路上描述了两个提案之间的确切交互。(背景参见 issue #3。)
我们提议需要新标志来启用字符串属性,以及允许新语法字符类包含多字符字符串元素(来自字符串字面量或类中使用的字符串属性)。
一个字符串属性能否变为字符属性,反之亦然?
简短回答:不能。
详细回答:我们在 2019 年 5 月向 Unicode 技术委员会(UTC)提出了这一点(参见 L2/19-168 + 会议记录),后来(2021 年 4 月)提出了一个具体的稳定性政策(参见 L2/21-091 + 会议记录)。UTC 达成共识批准了我们的提案。规范性或信息性 Unicode 属性的域绝不能改变。特别是,字符属性绝不能变为字符串属性,反之亦然。
一个属性或字符类能否匹配无限字符串集?
简短回答:不能。
本提案,就像原始的 字符串属性提案 一样,添加了对某些字符串属性的支持,每个属性扩展为有限的、明确定义的字符串集(Basic_Emoji 也适用于许多单字符);本提案添加了显式枚举字符串的字符类语法,这也创建了一个有限集。这是对有限字符属性和有限字符类/字符集的自然扩展。
例如,在 UTS #51 中有非常明确的区别:
- emoji zwj 序列,通过正则表达式定义,匹配无限字符串集
- RGI emoji ZWJ 序列集(= RGI_Emoji_ZWJ_Sequence 属性),这是 数据文件中列出的有限字符串集
理论上可以支持无限字符串集的命名匹配器,即一种命名子正则表达式。这明确不是本提案的一部分, 也未对此类假设表达式的语法和语义进行任何推测。
有足够的保留语法(例如,大括号)来支持未来广泛的扩展,但我们不打算在提议的规范更改中构建具体内容。
包含字符串的字符类的匹配顺序是什么?
本提案确保最长的字符串首先匹配,这样像 'xy' 这样的前缀不会隐藏像 'xyz' 这样的更长字符串。例如,模式 [a-c\q{W|xy|xyz}] 适用于字符串 'a'、'b'、'c'、'W'、'xy' 和 'xyz'。这个模式的行为类似于 xyz|xy|a|b|c|W 或 xyz|xy|[a-cW]。
最长字符串优先匹配是与 \p{RGI_Emoji} 等字符串属性集成的关键。Unicode 属性在数学意义上定义了一组字符/字符串;特别是,没有顺序。因此,例如在 [\p{RGI_Emoji}--\q{🇧🇪}] 中没有可保留的字符串顺序。
关于最长字符串优先匹配理由的更多细节,参见 issue #25。
一个字符类可能包含多个相同长度的字符串:例如 [xyz] 包含三个单字符字符串,[\q{xx|yy|zz}](使用新字符串字面量语法)包含三个双字符字符串。这些相同长度字符串没有固有或可观察的匹配顺序。委员会 讨论 并决定字符类是数学集,没有固有顺序。就像 [xyz] 和 [zyx] 在匹配顺序上没有可观察差异一样,[\q{xx|yy|zz}] 和 [\q{zz|yy|xx}] 在匹配顺序上也没有差异。这种细微差别使实现者可以使用集合(即数学集的实现)和字典树(检索树)进行运行时优化。
字符串属性是贪婪/原子性的吗?
不是。如上一个 FAQ 条目所示,\p{PropertyOfStrings} 脱糖为简单的析取,而不是包含析取的 原子组。我们认为这种行为是最面向未来的,原因如下。
如果,作为单独提案的一部分,原子组 按照其他语言的语法先例添加到 ECMAScript,用户可以做出自己的选择,即
- 如果希望原子行为,使用
(?>\p{PropertyOfStrings}) - 如果希望非原子行为,使用
\p{PropertyOfStrings}
另一方面,如果我们强制字符串属性是原子的,用户就没有办法选择退出原子行为,而无需发明一种在其他正则表达式风格中没有先例的新的“非原子”正则表达式运算符。
参见 issue #50 了解详情。
在 A--B 中,当 B 不是 A 的真子集时,减法如何表现?
如上一个问题的答案所述,根据当前 ECMAScript 规范和其他正则表达式实现,字符类是数学集合。因此,移除原始集合中不存在的字符串不是错误,而是无操作。示例(注意 RGI_Emoji 包含字符串 🇧🇪,但 RGI_Emoji_ZWJ_Sequence 不包含):
如果其中一个模式抛出异常,那将是令人困惑且适得其反的。
本解释器中的几个实际说明性示例 依赖这种有用的 A--B 模式,支持它至关重要。参见 issue #32 获取更多背景。
对称差呢?
我们也考虑过提议一个对称差运算符(参见 issue #5),但没有找到好的用例,并希望保持提案简单。
相反,我们提议保留双写 ASCII 标点符号和符号以供将来使用。这将允许未来的提案添加例如 ~~ 用于对称差,如 UTS #18 所建议的。
本提案是否影响 ECMAScript 词法分析?
不影响。我们提案的明确目标是,在提案之前正确的 ECMAScript 词法分析器在提案之后仍然是正确的 ECMAScript 词法分析器。
TC39 会议记录 + 幻灯片
- November 2020 (slides)
- January 2021 (slides)
- March 2021 (slides)
- April 2021 Incubator Call (slides)
- April 2021 (slides)
- May 2021 (slides)
- August 2021 (slides)
- December 2021 (slides)
- March 2022 (slides)
- May 2023 (slides)
规范
(我们最初在 Google 文档 中开发了草稿规范更改,但后来将所有更改从那里移到了拉取请求中。)
与其他标准的集成:
- 与 HTML 标准中
pattern属性的集成:https://github.com/whatwg/html/pull/7908 - 与
URLPatternAPI 的集成:https://github.com/WICG/urlpattern/issues/178
实现
- SpiderMonkey/Firefox,在 Firefox 116 中发布
- V8/Chrome,在 V8 v11.2 / Chrome 112 中默认启用(早期版本在
--harmony-regexp-unicode-sets标志后面) - JavaScriptCore/Safari,在 Safari Technology Preview 166 & Safari 17 中默认启用
- Babel 通过 regexpu-core
- ICU 类 UnicodeSet 可以从具有类似正则表达式字符类语法的字符串构建。UnicodeSet 长期以来支持集合运算和多字符字符串,最近(在 ICU 70 中)添加了 emoji 字符串属性的支持。
- C++ SRELL (
std::regex-like library)
对 HTML pattern 属性中的 v 标志的支持 可在以下环境中使用: