据我所知,JavaScript中没有命名的捕获组。获得类似功能的替代方法是什么?
当前回答
为捕获的组命名有一个好处:减少与复杂正则表达式的混淆。
这真的取决于你的用例,但也许漂亮地打印你的正则表达式会有所帮助。
或者您可以尝试定义常量来引用您捕获的组。
注释可能还有助于向阅读您代码的其他人展示您所做的工作。
至于其他的,我必须同意蒂姆的回答。
其他回答
在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 (ECMAScript 2018)!
命名捕获组很快就会出现在JavaScript中。 提案已经进入第三阶段。
捕获组可以使用(?<name>…)语法在尖括号内指定名称,用于 任何标识符名称。日期的正则表达式可以是 写成/(? <一> \ d{4})——(? <月> \ d{2})——(? <天> \ 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';
另一个可能的解决方案:创建一个包含组名和索引的对象。
var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };
然后,使用对象键来引用组:
var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];
这可以提高使用正则表达式结果的代码的可读性/质量,但不会提高正则表达式本身的可读性。
没有ECMAScript 2018?
我的目标是使它的工作尽可能类似于我们所习惯的命名组。而在ECMAScript 2018中,你可以在组中放置?<groupname>来表示一个命名组,在我的旧javascript解决方案中,你可以在组中放置(?!=<groupname>)来做同样的事情。所以它是一组额外的括号和一个额外的!=。很接近!
我把它都包装成一个字符串原型函数
特性
适用于较旧的javascript 没有额外的代码 使用起来非常简单 Regex仍然有效 组是在正则表达式本身中记录的 组名可以有空格 返回带有结果的对象
指令
将(?!={groupname})放置在您想要命名的每个组中 记住,通过在组的开头放置?:来消除任何非捕获组()。这些不会被命名。
arrays.js
// @@pattern - includes injections of (?!={groupname}) for each group
// @@returns - an object with a property for each group having the group's match as the value
String.prototype.matchWithGroups = function (pattern) {
var matches = this.match(pattern);
return pattern
// get the pattern as a string
.toString()
// suss out the groups
.match(/<(.+?)>/g)
// remove the braces
.map(function(group) {
return group.match(/<(.+)>/)[1];
})
// create an object with a property for each group having the group's match as the value
.reduce(function(acc, curr, index, arr) {
acc[curr] = matches[index + 1];
return acc;
}, {});
};
使用
function testRegGroups() {
var s = '123 Main St';
var pattern = /((?!=<house number>)\d+)\s((?!=<street name>)\w+)\s((?!=<street type>)\w+)/;
var o = s.matchWithGroups(pattern); // {'house number':"123", 'street name':"Main", 'street type':"St"}
var j = JSON.stringify(o);
var housenum = o['house number']; // 123
}
o的结果
{
"house number": "123",
"street name": "Main",
"street type": "St"
}
虽然不能使用普通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));