正则扩展

220 阅读2分钟

摘自《ES6标准入门 第三版》

  • 具名组匹配

有一个“具名匹配”的提案,其实允许为每一个组匹配指定一个名字,即便于阅读代码,又便于引用。

    const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
    
    const matchObj = RE_DATE.exec('2019-08-16');
    const year = matchObj.groups.year; // 2019
    const month = matchObj.groups.month; // 08
    const day = matchObj.groups.day; // 16

上面的代码中,“具名组匹配”在圆括号内部,在模式的头部添加“问好 + 尖括号 + 组名”(?),然后就可以在 exec 方法返回结果的 groups 属性上引用该组名。同时,数字序号(matchObj[1])依然有效。 具名组匹配等于为每一组匹配加上了 ID,这样便于描述匹配的目的。如果组的顺序变了,也不用改变匹配后的处理代码。 如果具名组没有匹配,那么对应的 groups 对象属性会是 undefined。

    const RE_OPT_A = /^(?<as>a+)?$/;
    const matchObj = RE_OPT_A.exec('');
    matchObj.groups.as // undefined
    'as' in matchObj.groups // true

上面的代码中,具名组 as 没有找到匹配,那么matchObj.groups.as 属性值就是 undefined,并且 as 这个键名在 groups 是始终存在的。

  • 解构赋值和替换

有了具名组匹配以后,可以使用解构赋值直接从匹配结果上为变量赋值。

    let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
    one // foo
    two // bar

字符串替换时,使用 $<组名> 引用具名组。

    let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u/;
    '2019-08-16'.replace(re, '$<day>/$<month>/$<year>') // 16-08-2019

上面的代码中,replace 方法的第二个参数是一个字符串,而不是正则表达式。replace 方法的第二个参数也可以是函数,该函数的参数序列如下。

    '2019-08-16'.replace(re, (
        matched, // 整个匹配结果 2019-08-16
        capture1, // 第一个组匹配 2019
        capture2, // 第二个组匹配 08
        capture3, // 第三个组匹配 16
        position, // 匹配开始的位置 0
        S, // 原字符串 2019-08-16
        groups, // 具名组构成的一个对象 {year, month, day};
    ) => {
        let {day, month, yaer} = args[args.length -1];
        return `${day}/${month}/${year}`
    });

具名组匹配在原来的基础上新增了最后一个函数参数:具名组构成的一个对象。函数内部可以直接对这个对象进行解构赋值。