For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-regexp-match-indices.md.
  • 简体中文
  • RegExp Match Indices S4

    中文标题:RegExp 匹配索引

    提案概览
    提案速览

    该提案在 RegExp.prototype.exec 等相关方法返回的数组结果上增加 indices 属性,提供每个捕获组相对于输入字符串的起始和结束索引。它引入了 d 标志,仅在需要时启用此功能以优化性能。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    ECMAScript 的 RegExp 匹配索引

    ECMAScript RegExp 匹配索引提供有关捕获的子字符串相对于输入字符串开头的起始和结束索引的额外信息。

    可以在 NPM 上的 regexp-match-indices 包中找到 polyfill。

    注意:此提案之前被称为“RegExp 匹配数组偏移”,但已重命名以更准确地反映提案的当前状态。

    状态

    阶段: 4 提案负责人: Ron Buckton (@rbuckton)

    有关此提案的详细状态,请参阅下面的 TODO

    作者

    • Ron Buckton (@rbuckton)

    动机

    目前,ECMAScript RegExp 对象在调用 exec 方法时可以提供有关_匹配_的信息。此结果是一个 Array,包含有关匹配的子字符串的信息,以及指示 input 字符串、匹配在输入中找到的 index 的附加属性,以及包含任何命名捕获组子字符串的 groups 对象。

    然而,在一些更高级的场景中,这些信息可能不一定足够。例如,ECMAScript 实现的 TextMate 语言语法高亮不仅需要匹配的 index,还需要单个捕获组的开始和结束索引。

    因此,我们建议在 RegExpBuiltInExec 抽象操作(以及因此 RegExp.prototype.exec()String.prototype.match 等的结果)的数组结果(子字符串数组)上增加一个 indices 属性。此属性本身将是一个_索引数组_,包含每个捕获的子字符串的起始和结束索引对。任何_未匹配的_捕获组将为 undefined,类似于它们在_子字符串数组_中的对应元素。此外,_索引数组_本身将具有一个 groups 属性,其中包含每个命名捕获组的开始和结束索引。

    注意:出于性能原因,仅在指定了 d 标志时才将 indices 添加到结果中。

    为什么使用 d 作为 RegExp 标志

    我们选择了 d,因为它出现在单词 indices 中,这是该功能命名的基础(即,RegExp 上的 lastIndex、匹配上的 index 等。字符 i 已用于忽略大小写,而 n 在其他引擎中已有处理捕获组与非捕获组的先例。这类似于“粘性”标志使用 y 字符,因为 s 已用于点号通配。

    为什么不用 ooffsets 而不是 dindices 我们的目标是将属性的名称与 RegExp 上现有的术语保持一致(即 lastIndexindex)。

    d 在其他引擎中是否有不同的含义? 是也不是。对于少数确实d 标志的引擎(Onigmo、Perl 和 java.util.regex),含义不同。Onigmo 和 Perl 都将 d 标志用于向后兼容性(而 Perl 的文档似乎强烈劝阻使用它),而 java.util.regex 使用 d 来处理换行处理。您可以在 flags_comparison.md 中找到 46 个不同 RegExp 引擎支持的所有标志的完整列表。

    现有技术

    示例

    const re1 = /a+(?<Z>z)?/d;
    
    // 索引相对于输入字符串的开头:
    const s1 = "xaaaz";
    const m1 = re1.exec(s1);
    m1.indices[0][0] === 1;
    m1.indices[0][1] === 5;
    s1.slice(...m1.indices[0]) === "aaaz";
    
    m1.indices[1][0] === 4;
    m1.indices[1][1] === 5;
    s1.slice(...m1.indices[1]) === "z";
    
    m1.indices.groups["Z"][0] === 4;
    m1.indices.groups["Z"][1] === 5;
    s1.slice(...m1.indices.groups["Z"]) === "z";
    
    // 未匹配的捕获组返回 `undefined`:
    const m2 = re1.exec("xaaay");
    m2.indices[1] === undefined;
    m2.indices.groups["Z"] === undefined;

    TODO

    以下是推进 TC39 提案流程 每个阶段所需的高级任务列表:

    阶段 1 进入标准

    • 确定一位“提案负责人”来推进此添加。
    • 概述问题或需求以及解决方案总体形态的散文
    • 使用方式的说明性示例
    • 高级API

    阶段 2 进入标准

    阶段 3 进入标准

    阶段 4 进入标准

    • 已为主要用例场景编写了 Test262 验收测试,并已合并
    • 两个通过验收测试的兼容实现:
      • V8(跟踪错误)— 在 Chrome Canary 91 中发布(V8 v9.0.259)
      • SpiderMonkey(跟踪错误)— 在 Firefox Nightly 88 中发布
      • JavaScriptCore(跟踪错误)— 在 Safari Technology Preview 122 中发布
      • Engine262(PR#1PR#2
    • 已向 tc39/ecma262 发送了集成规范文本的拉取请求
    • ECMAScript 编辑器已签署拉取请求