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


当前回答

正如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>

其他回答

有一个名为-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>

在ES6中,你可以使用数组解构来捕获你的组:

let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = regex.exec(text) || [];

// count === '27'
// unit === 'months'

注意:

最后一个let中的第一个逗号跳过结果数组的第一个值,即整个匹配的字符串 .exec()后的||[]将在没有匹配时防止析构错误(因为.exec()将返回null)

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

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

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

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

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

虽然不能使用普通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));