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

mmi*_*ins 189 javascript regex

据我所知,在JavaScript中没有名为捕获组的东西.获得类似功能的另一种方法是什么?

Tim*_*ker 105

ECMAScript 2018将命名捕获组引入JavaScript正则表达式.

如果您需要支持旧版浏览器,您可以使用正常(编号)捕获组执行所有操作,您可以使用命名捕获组执行操作,您只需要跟踪数字 - 如果在您的捕获组的顺序中这可能很麻烦正则表达式的变化.

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

  1. 在一些正则表达式中(.NET和JGSoft,据我所知),您可以在正则表达式中为不同的组使用相同的名称(有关这一事项的示例,请参阅此处).但是大多数正则表达式都不支持这种功能.

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

除此之外,命名捕获组只是"语法糖".仅在您真正需要时才使用捕获组,并(?:...)在所有其他情况下使用非捕获组.

使用JavaScript的更大问题(在我看来)是它不支持详细的正则表达式,这将使可读,复杂的正则表达式的创建更容易.

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

  • 最大的优点是:您可以只更改RegExp,无需数字到变量的映射.非捕获组解决了这个问题,除了一个案例:**如果组的顺序发生变化会怎么样?**此外,它还要将这些额外的字符放在其他组中... (100认同)
  • 所谓的**语法糖**_does_帮助提高了代码的可读性! (54认同)
  • 许多风格允许在正则表达式中多次使用相同的捕获组名称.但只有.NET和Perl 5.10+通过保持参与匹配的最后一个名称组捕获的值来使这一点特别有用. (5认同)
  • 截至2019年10月,Firefox,IE 11和Microsoft Edge(Chromium之前的版本)不支持命名组捕获。大多数其他浏览器(甚至Opera和Samsung mobile)都可以。https://caniuse.com/#feat=mdn-javascript_builtins_regexp_named_capture_groups (3认同)
  • 我认为命名捕获组还有另一个非常有价值的原因。例如,如果您想使用正则表达式从字符串中解析日期,您可以编写一个灵活的函数来获取值和正则表达式。只要正则表达式为年、月和日期命名了捕获,您就可以用最少的代码运行一组正则表达式。 (2认同)

小智 61

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

  • 添加新的正则表达式和替换文本语法,包括对命名捕获的全面支持.
  • 添加两个新的正则表达式标志:s,使点匹配所有字符(也称为dotall或单行模式),以及x自由间距和注释(也称为扩展模式).
  • 提供一系列功能和方法,使复杂的正则表达式处理变得轻而易举.
  • 自动修复正则表达式行为和语法中最常遇到的跨浏览器不一致性.
  • 允许您轻松创建和使用为XRegExp的正则表达式语言添加新语法和标志的插件.


Mr.*_* TA 56

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

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

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

var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];
Run Code Online (Sandbox Code Playgroud)

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


fre*_*nte 56

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

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

// count === '27'
// unit === 'months'
Run Code Online (Sandbox Code Playgroud)

注意:

  • 最后一个逗号let跳过结果数组的第一个值,即整个匹配的字符串
  • 当没有匹配时,|| []after .exec()会阻止解构错误(因为.exec()会返回null)

  • 对于那些具有转译或 ES6+ 目标的人,我最喜欢的答案是这里。如果例如重用的正则表达式更改,这不一定能防止不一致错误以及命名索引,但我认为这里的简洁很容易弥补这一点。在字符串可能为“null”或“undefined”的地方,我选择了“RegExp.prototype.exec”而不是“String.prototype.match”。 (2认同)

For*_*vin 19

更新:它最终成为JavaScript(ECMAScript 2018)!


命名捕获组可以很快进入JavaScript.
它的提议已经在第3阶段.

(?<name>...)对于任何标识符名称,可以使用语法在角括号内为捕获组指定名称.然后可以将日期的正则表达式写为/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u.每个名称都应该是唯一的,并遵循ECMAScript IdentifierName的语法.

可以从正则表达式结果的groups属性的属性访问命名组.也会创建对组的编号引用,就像非命名组一样.例如:

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';
Run Code Online (Sandbox Code Playgroud)


Yas*_*ima 6

命名捕获的组提供了一件事:与复杂的正则表达式混淆较少.

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

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

然后,评论可能也有助于向其他人展示您的代码,以及您所做的事情.

对于其他人,我必须同意蒂姆的回答.


Ham*_*deh 6

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

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

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

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

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

var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/
Run Code Online (Sandbox Code Playgroud)
let result = regexObj.exec('2019-28-06 year is 2019');
// result.groups.year === '2019';
// result.groups.month === '06';
// result.groups.day === '28';
Run Code Online (Sandbox Code Playgroud)
  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;
}
Run Code Online (Sandbox Code Playgroud)


chi*_*org 5

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

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