RegExp named capture groups S4
中文标题:正则表达式命名捕获组
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2018
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案通过 (?
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
正则表达式命名捕获组
阶段 4
提案发起人:Daniel Ehrenberg (Igalia) & Mathias Bynens (Google)
简介
编号捕获组允许人们引用正则表达式匹配的字符串的某些部分。每个捕获组被分配一个唯一的号码,并且可以通过该号码进行引用,但这可能使正则表达式难以理解和重构。
例如,给定匹配日期的 /(\d{4})-(\d{2})-(\d{2})/,如果不检查周围的代码,就无法确定哪个组对应月份,哪个组对应日。此外,如果要交换月份和日的顺序,组引用也必须更新。
命名捕获组为这些问题提供了一个很好的解决方案。
高层 API
捕获组可以使用 (?<name>...) 语法为任何标识符 name 命名。日期的正则表达式可以写成 /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u。每个名称应该唯一,并遵循 ECMAScript IdentifierName 的语法。
命名组可以从正则表达式结果的 groups 属性的属性中访问。也会创建对组的编号引用,就像对待非命名组一样。例如:
该接口与解构配合得很好,如下例所示:
反向引用
命名组可以在正则表达式内通过 \k<name> 构造访问。例如,
命名引用也可以与编号引用同时使用。
替换目标
命名组也可以从传给 String.prototype.replace 的替换值中引用。如果该值是字符串,可以使用 $<name> 语法访问命名组。例如:
请注意,传给 replace 的是普通字符串字面量,而不是模板字面量,因为该方法会解析 day 等的值,而不是将它们作为局部变量。另一种选择是使用 ${day} 语法(同时保持不是模板字符串);本提案使用 $<day> 是为了与组的定义相呼应,并与模板字面量区分开来。
如果 String.prototype.replace 的第二个参数是函数,则命名组可以通过名为 groups 的新参数访问。新签名将是 function (matched, capture1, ..., captureN, position, S, groups)。命名捕获组仍然像往常一样参与编号。例如:
细节
重叠的组名
RegExp 结果对象已经有了一些非数字属性,命名捕获组可能与这些属性重叠,即 length、index 和 input。在本提案中,为了避免重叠名称带来的歧义和边缘情况,命名组属性被放置在单独的 groups 对象上,该对象是匹配对象的属性。这个解决方案将允许在未来的 ECMAScript 版本中向 exec 的结果添加额外的属性,而不会产生任何 Web 兼容性风险。
仅对具有命名组的 RegExp 创建 groups 对象。它不包含编号组属性,只包含命名组属性。对于 RegExp 中提到的所有组,都会在 groups 对象上创建属性;如果在匹配中未遇到这些组,则值为 undefined。
新语法向后兼容性
创建新命名组的语法 /(?<name>)/ 目前在任何 ECMAScript 正则表达式中都是语法错误,因此可以添加到所有正则表达式中而不会产生歧义。但是,命名反向引用语法 /\k<foo>/ 目前在非 Unicode 正则表达式中是允许的,并且匹配字面字符串 "k<foo>"。在 Unicode 正则表达式中,这种转义是被禁止的。
在本提案中,非 Unicode 正则表达式中的 \k<foo> 将继续匹配字面字符串 "k<foo>",除非正则表达式包含命名组,在这种情况下,它将匹配该组或成为语法错误,具体取决于正则表达式是否有一个名为 foo 的命名组。这不影响现有代码,因为目前没有有效的正则表达式可以包含命名组。这将是一个重构风险,尽管仅对于在正则表达式中包含 \k 的代码。
其他编程语言中的先例
本提案类似于许多其他编程语言对命名捕获组的处理方式。这似乎是共识语法的发展方向,尽管 Python 的语法是一个有趣且引人注目的例外,它可以解决非 Unicode 反向引用问题。
Perl 参考
Perl 使用与本提案相同的语法来处理命名捕获组 /(?<name>)/ 和反向引用 /\k<name>/。
Python 参考
命名捕获组使用语法 "(?P<name>)",并有反向引用 (?P=name)。
Java 参考
JDK7+ 支持与 Perl 和本提案类似的语法来命名捕获组。
.NET 参考
C# 和 VB.NET 支持使用语法 "(?<name>)" 以及 "(?'name')" 来命名捕获组,并使用 "\k<name>" 进行反向引用。
PHP
根据 Stack Overflow 帖子 和 php.net 文档上的评论,PHP 长期以来一直支持使用语法 "(?P<foo>)" 的命名组,该语法可作为结果匹配对象的属性使用。
Ruby 参考
Ruby 的语法与 .NET 相同,支持使用语法 "(?<name>)" 以及 "(?'name')" 来命名捕获组,并使用 "\k<name>" 进行反向引用。
规范草案
实现
- V8,随 Chrome 64 发布
- XS,在 2018 年 1 月 17 日更新 中
- 转译器(Babel 插件)
- Safari 从 Safari Technology Preview 40 开始