据我所知,JavaScript 中没有命名捕获组这样的东西。获得类似功能的替代方法是什么?
在 JavaScript 正则表达式中命名捕获组?
ECMAScript 2018 将命名捕获组引入 JavaScript 正则表达式。
例子:
const auth = 'Bearer AUTHORIZATION_TOKEN'
const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth)
console.log(token) // "Prints AUTHORIZATION_TOKEN"
如果您需要支持较旧的浏览器,您可以使用普通(编号)捕获组执行命名捕获组可以执行的所有操作,您只需要跟踪数字 - 如果捕获组的顺序在您的正则表达式更改。
我能想到的命名捕获组只有两个“结构”优势:
在某些正则表达式风格(.NET 和 JGSoft,据我所知)中,您可以对正则表达式中的不同组使用相同的名称(有关此问题的示例,请参见此处)。但无论如何,大多数正则表达式都不支持此功能。
如果您需要在被数字包围的情况下引用编号的捕获组,则可能会出现问题。假设您要向数字添加零,因此要替换
(\d)
为$10
。在 JavaScript 中,这会起作用(只要您的正则表达式中的捕获组少于 10 个),但 Perl 会认为您正在寻找反向引用 number10
而不是 number1
,后跟0
. 在 Perl 中,您可以${1}0
在这种情况下使用。
除此之外,命名的捕获组只是“语法糖”。仅在您真正需要它们时才使用捕获组,并(?:...)
在所有其他情况下使用非捕获组,这会有所帮助。
JavaScript 的更大问题(在我看来)是它不支持冗长的正则表达式,这会使创建可读的、复杂的正则表达式变得容易得多。
Steve Levithan 的 XRegExp 库解决了这些问题。
另一种可能的解决方案:创建一个包含组名和索引的对象。
var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };
然后,使用对象键来引用组:
var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];
这使用正则表达式的结果提高了代码的可读性/质量,但不是正则表达式本身的可读性。
在 ES6 中,您可以使用数组解构来捕获您的组:
let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = regex.exec(text) || [];
// count === '27'
// unit === 'months'
注意:
- 最后一个逗号
let
跳过结果数组的第一个值,这是整个匹配的字符串 - 当没有匹配项时,
|| []
after.exec()
将防止解构错误(因为.exec()
将返回null
)
更新:它终于变成了 JavaScript (ECMAScript 2018)!
命名的捕获组很快就会进入 JavaScript。
它的提案已经处于第 3 阶段。
(?<name>...)
对于任何标识符名称,可以使用语法在尖括号内为捕获组指定一个名称。日期的正则表达式可以写成/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
. 每个名称都应该是唯一的,并遵循 ECMAScript IdentifierName的语法。
命名组可以从正则表达式结果的组属性的属性中访问。与未命名的组一样,还会创建对组的编号引用。例如:
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';