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


当前回答

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

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

其他回答

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

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

你可以使用XRegExp,一个扩展的、可扩展的、跨浏览器的正则表达式实现,包括对额外语法、标志和方法的支持:

Adds new regex and replacement text syntax, including comprehensive support for named capture. Adds two new regex flags: s, to make dot match all characters (aka dotall or singleline mode), and x, for free-spacing and comments (aka extended mode). Provides a suite of functions and methods that make complex regex processing a breeze. Automagically fixes the most commonly encountered cross-browser inconsistencies in regex behavior and syntax. Lets you easily create and use plugins that add new syntax and flags to XRegExp's regular expression language.

在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)

另一个可能的解决方案:创建一个包含组名和索引的对象。

var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };

然后,使用对象键来引用组:

var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];

这可以提高使用正则表达式结果的代码的可读性/质量,但不会提高正则表达式本身的可读性。

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