ES9(ES2018)中的正则表达式

ES9中正则表达式相关主要有两个提案:正则表达式命名捕获组 & 正则表达式dotAll模式,目前都已进入stage4阶段。

正则表达式命名捕获组

ECMAScript提案“正则表达式命名捕获组”proposal-regexp-named-group 由 Gorkem Yakin, Daniel Ehrenberg负责。

1. 什么是捕获组

捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显示命名的组里,方便后面引用,且这种引用既可以在正则表达式内部,也可以在正则表达式外部。

捕获组有两种形式,一种是普通捕获组,另一种是命名捕获组。

目前JavaScript只支持数字形式的普通捕获组,而这个提案就是为了给JavaScript增加命名捕获组。

2.捕获组编号规则

编号规则指的是以数字为捕获组进行编号的规则, 编号0的捕获组代表正则表达式整体。

const regex = /(\d{4})-(\d{2})-(\d{2})/;
const matchers = regex.exec('2020-12-02');
console.table(matchers)

image.png

3.命名捕获组

使用数字捕获组的一个缺点是对于引用不太直观。比如上面的例子,我们相对比较难分清楚哪个组代表年,哪个组代表月或者日。而且,当我们交互了年和月的值时,使用捕获组引用的代码都需要更改。

而命名捕获组就是为了解决这个问题。

命名捕获组可以使用(?...)语法给每个组起个名称。因此,用来匹配日期的正则表达式可以写为:

/(?\d{4})-(?\d{2})-(?\d{2})/

每个捕获组的名字必须唯一,否则会抛出异常:
image.png

命名捕获组可以通过匹配结果的groups 属性访问。

let regx = /(?\d{4})-(?\d{2})-(?\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 = /^(?.*):(?.*)$/;
let {groups: {one, two}} = regx.exec('foo:bar');
console.log(`one: ${one}, two: ${two}`);

4.反向引用

当需要在正则表达式里面引用命名捕获组时,使用\k语法。

let duplicate = /^(?.*).\k$/;
duplicate.test('a*b'); // false
duplicate.test('a*a'); // true

如果引用一个不存在的命名捕获组,会抛出异常:
image.png
命名捕获组也可以和普通数字捕获组一起使用:

let triplicate = /^(?.*).\k.\1$/;
triplicate.test('a*a*a'); // true
triplicate.test('a*a*b'); // false

5.替换

命名捕获组也可以在String.prototype.replace函数中引用,使用$语法。

let regx = /(?\d{4})-(?\d{2})-(?\d{2})/;
let result = "2020-12-02".replace(regx, '$/$/$');

console.log(result === '02/12/2020');

String.prototype.replace第2个参数可以接受一个函数。这时,命名捕获组的引用会作为 groups参数传递进取。

第2个参数的函数签名是function (matched, capture1, ..., captureN, position, S, groups)

let regx = /(?\d{4})-(?\d{2})-(?\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';

6.命名捕获组未匹配

如果一个可选的命名捕获组没有匹配时,在匹配结果中,此命名组依然存在,值是undefined

let regx = /^(?\d+)?$/;
let matchers = regx.exec('');

matcher[0] === '';
matchers.groups.optional === undefined;

如果捕获组不是可选的,匹配结果是null

let regx = /^(?\d+)$/;
let matchers = regx.exec('');

matchers === null;

7. 向下兼容

/(?)//\k/只有在命名捕获组中才有意义。如果正则表达式没有命名捕获组,那么/\k/仅仅是字符串字面量"k"而已。

8. 实现

正则表达式dotAll模式

你可能感兴趣的:(正则表达式)