ES9中正则表达式相关主要有两个提案:正则表达式命名捕获组 & 正则表达式dotAll模式,目前都已进入stage4阶段。html
ECMAScript提案“正则表达式命名捕获组”proposal-regexp-named-group 由 Gorkem Yakin, Daniel Ehrenberg负责。java
捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显示命名的组里,方便后面引用,且这种引用既能够在正则表达式内部,也能够在正则表达式外部。git
捕获组有两种形式,一种是普通捕获组,另外一种是命名捕获组。github
目前JavaScript只支持数字形式的普通捕获组,而这个提案就是为了给JavaScript增长命名捕获组。正则表达式
编号规则指的是以数字为捕获组进行编号的规则, 编号0的捕获组表明正则表达式总体。babel
const regex = /(\d{4})-(\d{2})-(\d{2})/; const matchers = regex.exec('2020-12-02'); console.table(matchers)
使用数字捕获组的一个缺点是对于引用不太直观。好比上面的例子,咱们相对比较难分清楚哪一个组表明年,哪一个组表明月或者日。并且,当咱们交互了年和月的值时,使用捕获组引用的代码都须要更改。app
而命名捕获组就是为了解决这个问题。函数
命名捕获组可使用(?<name>...)语法给每一个组起个名称。所以,用来匹配日期的正则表达式能够写为:spa
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
每一个捕获组的名字必须惟一,不然会抛出异常:
另外,捕获组的名字必须符合JavaScript命名规范:prototype
命名捕获组能够经过匹配结果的groups
属性访问。
let regx = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; let result = regx.exec('2020-12-02'); result.groups.year === '2020'; result.groups.month === '12'; result.groups.day === '02'; result[0] === '2020-12-02'; result[1] === '2020'; result[2] === '12'; result[3] === '02';
使用解构赋值的例子:
let regx = /^(?<one>.*):(?<two>.*)$/; let {groups: {one, two}} = regx.exec('foo:bar'); console.log(`one: ${one}, two: ${two}`);
当须要在正则表达式里面引用命名捕获组时,使用\k<name>
语法。
let duplicate = /^(?<half>.*).\k<half>$/; duplicate.test('a*b'); // false duplicate.test('a*a'); // true
若是引用一个不存在的命名捕获组,会抛出异常:
命名捕获组也能够和普通数字捕获组一块儿使用:
let triplicate = /^(?<part>.*).\k<part>.\1$/; triplicate.test('a*a*a'); // true triplicate.test('a*a*b'); // false
命名捕获组也能够在String.prototype.replace
函数中引用,使用$<name>
语法。
let regx = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; let result = "2020-12-02".replace(regx, '$<day>/$<month>/$<year>'); console.log(result === '02/12/2020');
String.prototype.replace
第2个参数能够接受一个函数。这时,命名捕获组的引用会做为 groups
参数传递进取。
第2个参数的函数签名是function (matched, capture1, ..., captureN, position, S, groups)
。
let regx = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; let result = '2020-12-02'.replace(regx, (...args)=>{ let { day, month, year } = args[args.length - 1]; return `${day}/${month}/${year}` }); result === '02/12/2020';
若是一个可选的命名捕获组没有匹配时,在匹配结果中,此命名组依然存在,值是undefined
。
let regx = /^(?<optional>\d+)?$/; let matchers = regx.exec(''); matcher[0] === ''; matchers.groups.optional === undefined;
若是捕获组不是可选的,匹配结果是null
。
let regx = /^(?<foo>\d+)$/; let matchers = regx.exec(''); matchers === null;
/(?<name>)/
和/\k<name>/
只有在命名捕获组中才有意义。若是正则表达式没有命名捕获组,那么/\k<name>/
仅仅是字符串字面量"k<name>"
而已。