正则表达式Javascript捕获组与量词不起作用

3

我有一个不错的正则表达式:

 *(?:(?:([0-9]+)(?:d| ?days?)(?:, ?| )?)|(?:([0-9]+)(?:h| ?hours?)(?:, ?| )?)|(?:([0-9]+)(?:m| ?minutes?)(?:, ?| )?)|(?:([0-9]+)(?:s| ?seconds?)(?:, ?| )?))+

这基本上是与人类可读的时间差匹配的正则表达式。它适用于PHP、Python和Go,但出于某种原因,在Javascript上捕获组不起作用。这里是regex101上工作正常的PHP示例,显示了工作正常的捕获组。您会注意到,在将其更改为javascript(ECMAscript)模式后,捕获组只会捕获最后一个值。有人可以帮忙解释一下我哪里做错了,以及为什么它在js上不起作用吗?

1个回答

3
这是一个更简单的例子,展示了这个问题:

console.log(
  '34'.match(/(?:(3)|(4))+/)
);

在PHP中,每当匹配到一个捕获组,它就会被放入结果中。相比之下,在JavaScript中,情况就更加复杂了:当一侧的备选项|有捕获组时,每当输入整个备选项标记时,就有两种可能性:
  • 取出的备选项包含捕获组,并且结果将捕获组索引设置为匹配的值。
  • 取出的备选项不包含捕获组,在这种情况下,结果将分配给该索引的undefined - 即使先前已匹配捕获组也是如此。
这在规范中描述如下:https://tc39.es/ecma262/#sec-disjunction

在由|跳过的模式部分内的任何捕获括号都生成未定义的值,而不是字符串。

以及

RepeatMatcher的步骤4每次重复Atom时都会清除Atom的捕获

因为最外层*的每次迭代都会清除量化的Atom中包含的所有捕获字符串


在您的情况下,最简单的修改方法是移除最外层重复的捕获组,这样只会一次匹配一个子序列,例如1m,然后1d,然后迭代匹配结果,而不是尝试在一次操作中匹配所有内容。为了确保所有匹配都相邻(例如1m1d而不是1m 1d),在迭代匹配结果时检查index是否与先前的匹配相邻。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接