const auth = 'Bearer AUTHORIZATION_TOKEN'
const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth)
console.log(token) // "AUTHORIZATION_TOKEN"
$ 10 替换(\ d)。在JavaScript中,这将起作用(只要您的正则表达式中捕获组少于10个),但Perl会认为您正在寻找反向引用号码 10 而不是号码 1 ,后跟 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
中的第一个逗号会跳过结果数组中的第一个值,该值是整个匹配字符串。.exec()
之后的|| []
将在没有匹配项(因为.exec()
将返回null
)时防止解构错误。String.prototype.match
返回一个数组,其中包含整个匹配的字符串在位置0,然后是其后的任何分组。第一个逗号表示“跳过位置0上的元素”。 - fregantenull
或 undefined
的地方使用 RegExp.prototype.exec
而不是 String.prototype.match
。 - Mike Hill更新:它最终已经被纳入JavaScript(ECMAScript 2018)了!
命名捕获组很快就可能被加入到JavaScript中。
该提案已经处于第三阶段。
使用(?<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';
let {year, month, day} = ((result) => ((result) ? result.groups : {}))(re.exec('2015-01-02'));
- Hashbrownlet {year, month, day} = {...re.exec('2015-01-02')?.groups};
- Robert\k<name>
。例如:var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/
正如Forivin所说,您可以按照以下方式在对象结果中使用捕获组:
let result = regexObj.exec('2019-28-06 year is 2019');
// result.groups.year === '2019';
// result.groups.month === '06';
// result.groups.day === '28';
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;
}
td, th{
border: solid 2px #ccc;
}
<input id="tinput" type="text" value="2019-28-06 year is 2019"/>
<br/>
<br/>
<span>Pattern: "(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>";
<br/>
<br/>
<button onclick="check()">Check!</button>
<br/>
<br/>
<table>
<thead>
<tr>
<th>
<span>Year</span>
</th>
<th>
<span>Month</span>
</th>
<th>
<span>Day</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span id="year"></span>
</td>
<td>
<span id="month"></span>
</td>
<td>
<span id="day"></span>
</td>
</tr>
</tbody>
</table>
给捕获组命名的唯一作用是减少在复杂正则表达式中的混乱。
这真的取决于您的使用情况,但也许漂亮地打印您的正则表达式可以帮助您。
或者您可以尝试定义常量来引用您的捕获组。
注释可能还有助于向阅读您的代码的其他人展示您所做的事情。
对于剩下的部分,我必须同意Tim的答案。
没有ECMAScript 2018吗?
我的目标是使其尽可能类似于我们使用命名组的方式。在ECMAScript 2018中,您可以在组内放置?<groupname>
以指示命名组,在我为旧版javascript提供的解决方案中,您可以在组内放置(?!=<groupname>)
以实现同样的效果。因此,这是额外的一组括号和一个额外的!=
。相当接近!
我将所有内容都包装到了一个字符串原型函数中
特点
说明
(?!={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));
var assocArray = Regex("hello alex, I am dennis", "hello ({hisName}.+), I am ({yourName}.+)");
- ForivinRegExp
对象的原型添加函数来扩展它。 - Mr. TA