在JavaScript正则expression式中命名捕获组?

据我所知,在JavaScript中没有命名捕获组这样的事情。 什么是获得类似function的替代方法?

一般来说,您可以使用正常(编号)的捕获组完成所有工作,您可以使用命名捕获组,只需跟踪数字即可。

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

  1. 在一些正则expression式(.NET和JGSoft,据我所知),你可以在你的regex中为不同的组使用相同的名字( 参见这里的一个例子 )。 但大多数正则expression式不支持这个function。

  2. 如果您需要在被数字包围的情况下引用编号的捕获组,则可能会出现问题。 假设你想给一个数字添加一个零,因此想用$10replace(\d) 。 在JavaScript中,这将起作用(只要您的正则expression式中的捕获组less于10个),但Perl会认为您正在寻找反向引用编号10而不是数字1 ,然后是0 。 在Perl中,在这种情况下可以使用${1}0

除此之外,命名捕捉组只是“语法糖”。 只有在真正需要它们时才使用捕获组,并且在所有其他情况下使用非捕获组(?:...)

JavaScript的问题在于,它不支持冗长的正则expression式,这将使创build易读,复杂的正则expression式变得更容易。

您可以使用XRegExp ,这是一个扩展的,可扩展的正则expression式的跨浏览器实现,包括对其他语法,标志和方法的支持:

  • 添加新的正则expression式和replace文本语法,包括对命名捕捉的全面支持。
  • 添加两个新的正则expression式标志: s ,使点匹配所有字符(又名dotall或单行模式)和x ,用于自由间距和注释(又名扩展模式)。
  • 提供一套function和方法,使复杂的正则expression式处理变得轻而易举。
  • 自动修复正则expression式行为和语法中最常遇到的跨浏览器不一致问题。
  • 让您轻松创build和使用插件,为XRegExp的正则expression式语言添加新的语法和标志。

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

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

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

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

这使用正则expression式的结果提高了代码的可读性/质量,而不是正则expression式本身的可读性。

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

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

注意:

  • 最后的第一个逗号是跳过结果数组的第一个值,这是整个匹配的string
  • || [] || [] .match()将会阻止解构错误,因为.match()将返回null

命名捕获的组提供了一件事情:减less与复杂正则expression式的混淆。

这真的取决于你的用例,但也许漂亮,打印你的正则expression式可以帮助。

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

评论可能也有助于向其他读者展示你的代码,你做了什么。

其余的我必须同意Tim的回答。

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

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

虽然你不能用香草JavaScript做到这一点,也许你可以使用一些Array.prototype函数,如Array.prototype.reduce ,使用一些魔术将索引匹配变成指定的匹配。

很明显,下面的解决scheme将需要按顺序进行匹配:

 // @text Contains the text to match // @regex A regular expression object (fe /.+/) // @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 ([az]+), I am ([az]+)/i, ["firstPersonName", "secondPersonName"] ); alert(JSON.stringify(namedMatches)); 

命名捕获组可能会很快成为JavaScript。
提案已经在第三阶段。

捕获组可以使用(?…)语法给定一个名称,用于任何标识符名称。 date的正则expression式可以写成/(?\ d {4}) – (?\ d {2}) – (?\ d {2})/ u。 每个名称应该是唯一的,并遵循ECMAScript IdentifierName的语法。

命名组可以从正则expression式结果的组属性的属性访问。 编号的参考也创build,就像非命名组。 例如:

 let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u; let result = re.exec('2015-01-02'); // result.groups.year === '2015'; // result.groups.month === '01'; // result.groups.day === '02'; // result[0] === '2015-01-02'; // result[1] === '2015'; // result[2] === '01'; // result[3] === '02';