JavaScript正则表达式和子匹配

Cha*_*ira 68 javascript regex

为什么Javascript子匹配在设置g修饰符时停止工作?

var text = 'test test test test';

var result = text.match(/t(e)(s)t/);
// Result: ["test", "e", "s"]
Run Code Online (Sandbox Code Playgroud)

上述工作正常,result[1]"e"result[2]"s".

var result = text.match(/t(e)(s)t/g);
// Result: ["test", "test", "test", "test"]
Run Code Online (Sandbox Code Playgroud)

以上忽略了我的捕获组.以下是唯一有效的解决方案吗?

var result = text.match(/test/g);
for (var i in result) {
    console.log(result[i].match(/t(e)(s)t/));
}
/* Result:
["test", "e", "s"]
["test", "e", "s"]
["test", "e", "s"]
["test", "e", "s"]
*/
Run Code Online (Sandbox Code Playgroud)

hbw*_*hbw 95

如果设置了全局修改器,使用Stringmatch()函数将不会返回捕获的组,如您所知.

在这种情况下,您可能希望使用RegExp对象并调用其exec()函数.Stringmatch()几乎是相同RegExpexec(),除了在这样的情况下功能.......如果全局修改设置,正常的match()功能将不返回拍摄组,而RegExpexec()功能.(在这里注明,等等.)

要记住的另一个问题是,exec()不会在一个大数组中返回匹配 - 它会一直保持返回匹配,直到它用完为止,在这种情况下它会返回null.

所以,例如,你可以这样做:

var pattern = /t(e)(s)t/g;  // Alternatively, "new RegExp('t(e)(s)t', 'g');"
var match;    

while (match = pattern.exec(text)) {
    // Do something with the match (["test", "e", "s"]) here...
}
Run Code Online (Sandbox Code Playgroud)

另外要注意的是,RegExp.prototype.exec()RegExp.prototype.test()执行上提供的字符串的正则表达式,返回的第一个结果.每个顺序调用将RegExp.prototype.lastIndex根据字符串中的当前位置逐步执行结果集更新.

这是一个例子://记住示例和模式中有4个匹配项.lastIndex从0开始

pattern.test(text); // pattern.lastIndex = 4
pattern.test(text); // pattern.lastIndex = 9
pattern.exec(text); // pattern.lastIndex = 14
pattern.exec(text); // pattern.lastIndex = 19

// if we were to call pattern.exec(text) again it would return null and reset the pattern.lastIndex to 0
while (var match = pattern.exec(text)) {
    // never gets run because we already traversed the string
    console.log(match);
}

pattern.test(text); // pattern.lastIndex = 4
pattern.test(text); // pattern.lastIndex = 9

// however we can reset the lastIndex and it will give us the ability to traverse the string from the start again or any specific position in the string
pattern.lastIndex = 0;

while (var match = pattern.exec(text)) {
    // outputs all matches
    console.log(match);
}
Run Code Online (Sandbox Code Playgroud)

您可以在MDN上找到有关如何使用RegExp对象的信息(具体来说,这是函数的文档).exec()

  • 使用exec似乎不听g修饰符,但它支持子匹配/组.所以结果将是第一场比赛(它基本上忽略了g修饰符) (3认同)
  • 注意其他人遇到另一个问题:如果在它之前使用`.test()`,请确保在`while`循环之前使用`pattern.lastIndex = 0`重置lastIndex以获得所有匹配 (3认同)
  • 不是最优雅的解决方案.我期待输出有点像这样:[["test","e","s"],["test","e","s"],["test","e","s" ],["test","e","s"]] (2认同)
  • g标志不会被忽略。它必须在那里,否则您将陷入无限循环。在这里找到困难的方法:) (2认同)

Cha*_*ira 6

我很惊讶地发现我是第一个用 10 年前我一直在寻找的答案来回答这个问题的人(答案还不存在)。我也希望实际的规范编写者能在我之前回答这个问题;)。

.matchAll已添加到一些浏览器中。

在现代 javascript 中,我们现在只需执行以下操作即可完成此任务。

let result = [...text.matchAll(/t(e)(s)t/g)];
Run Code Online (Sandbox Code Playgroud)

.matchAll 规格

.matchAll 文档

我现在维护一个同构 javascript 库,它可以帮助进行很多此类字符串解析。您可以在这里查看:string-saw。在使用命名捕获组时,它有助于使 .matchAll 更易于使用。

一个例子是

saw(text).matchAll(/t(e)(s)t/g)
Run Code Online (Sandbox Code Playgroud)

它会输出更加用户友好的匹配数组,如果您想要更奇特,您可以放入命名捕获组并获取对象数组。