据我所知,JavaScript中没有命名的捕获组。获得类似功能的替代方法是什么?


当前回答

为捕获的组命名有一个好处:减少与复杂正则表达式的混淆。

这真的取决于你的用例,但也许漂亮地打印你的正则表达式会有所帮助。

或者您可以尝试定义常量来引用您捕获的组。

注释可能还有助于向阅读您代码的其他人展示您所做的工作。

至于其他的,我必须同意蒂姆的回答。

其他回答

虽然不能使用普通JavaScript实现这一点,但也许可以使用一些Array。prototype函数,如Array.prototype.reduce,使用一些魔法将索引匹配转换为命名匹配。

显然,下面的解决方案需要匹配顺序:

// @text Contains the text to match // @regex A regular expression object (f.e. /.+/) // @matchNames An array of literal strings where each item // is the name of each group function namedRegexMatch(text, regex, matchNames) { var matches = regex.exec(text); return matches.reduce(function(result, match, index) { if (index > 0) // This substraction is required because we count // match indexes from 1, because 0 is the entire matched string result[matchNames[index - 1]] = match; return result; }, {}); } var myString = "Hello Alex, I am John"; var namedMatches = namedRegexMatch( myString, /Hello ([a-z]+), I am ([a-z]+)/i, ["firstPersonName", "secondPersonName"] ); alert(JSON.stringify(namedMatches));

ECMAScript 2018在JavaScript正则表达式中引入了命名捕获组。

例子:

  const auth = 'Bearer AUTHORIZATION_TOKEN'
  const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth)
  console.log(token) // "AUTHORIZATION_TOKEN"

如果您需要支持旧的浏览器,您可以使用普通的(编号的)捕获组来完成您可以使用命名捕获组来完成的所有事情,您只需要跟踪数字—如果正则表达式中捕获组的顺序发生了变化,这可能会很麻烦。

我能想到的命名捕获组只有两个“结构性”优势:

In some regex flavors (.NET and JGSoft, as far as I know), you can use the same name for different groups in your regex (see here for an example where this matters). But most regex flavors do not support this functionality anyway. If you need to refer to numbered capturing groups in a situation where they are surrounded by digits, you can get a problem. Let's say you want to add a zero to a digit and therefore want to replace (\d) with $10. In JavaScript, this will work (as long as you have fewer than 10 capturing group in your regex), but Perl will think you're looking for backreference number 10 instead of number 1, followed by a 0. In Perl, you can use ${1}0 in this case.

除此之外,命名捕获组只是“语法糖”。只有在真正需要时才使用捕获组,在所有其他情况下使用非捕获组(?:…)会有所帮助。

JavaScript最大的问题(在我看来)是它不支持冗长的正则表达式,这使得创建可读的复杂正则表达式变得容易得多。

Steve Levithan的XRegExp库解决了这些问题。

为捕获的组命名有一个好处:减少与复杂正则表达式的混淆。

这真的取决于你的用例,但也许漂亮地打印你的正则表达式会有所帮助。

或者您可以尝试定义常量来引用您捕获的组。

注释可能还有助于向阅读您代码的其他人展示您所做的工作。

至于其他的,我必须同意蒂姆的回答。

有一个名为-regexp的node.js库,你可以在你的node.js项目中使用它(在浏览器中通过使用browserify或其他打包脚本打包该库)。但是,该库不能用于包含未命名捕获组的正则表达式。

如果在正则表达式中计算开头捕获花括号,则可以在正则表达式中的命名捕获组和编号捕获组之间创建映射,并且可以自由混合和匹配。在使用正则表达式之前,只需删除组名。我写了三个函数来证明这一点。请看这个要点:https://gist.github.com/gbirke/2cc2370135b665eee3ef

正如Tim Pietzcker所说,ECMAScript 2018在JavaScript正则表达式中引入了命名捕获组。 但是我在上面的答案中没有发现如何在正则表达式本身中使用已命名的捕获组。

您可以使用以下语法使用命名捕获组:\k<name>。 例如

var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/

正如Forivin所说,你可以在对象结果中使用捕获组,如下所示:

let result = regexObj.exec('2019-28-06 year is 2019');
// result.groups.year === '2019';
// result.groups.month === '06';
// result.groups.day === '28';

var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/mgi; function check(){ var inp = document.getElementById("tinput").value; let result = regexObj.exec(inp); document.getElementById("year").innerHTML = result.groups.year; document.getElementById("month").innerHTML = result.groups.month; document.getElementById("day").innerHTML = result.groups.day; } td, th{ border: solid 2px #ccc; } <input id="tinput" type="text" value="2019-28-06 year is 2019"/> <br/> <br/> <span>Pattern: "(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>"; <br/> <br/> <button onclick="check()">Check!</button> <br/> <br/> <table> <thead> <tr> <th> <span>Year</span> </th> <th> <span>Month</span> </th> <th> <span>Day</span> </th> </tr> </thead> <tbody> <tr> <td> <span id="year"></span> </td> <td> <span id="month"></span> </td> <td> <span id="day"></span> </td> </tr> </tbody> </table>