match
,matchAll
和exec
的区别match,matchAll作用在字符串上,exec作用在正则表达式上
match匹配g模式的正则时返回的是匹配到的所有字符组成的数组;
匹配非g模式的正则时返回的数组的第一个是匹配到的,其余的是括号里捕获到的字符串。
exec匹配g模式的正则时返回的数组和match匹配的非g模式正则返回值相同;
在g模式下,exec会记录匹配,会将上次成功匹配后的位置记录在正则表达式的lastIndex
属性中,下一次匹配会从那开始。
matchAll只能匹配g模式,且返回一个迭代器,可以通过for...of Array.from 扩展运算符
来操作,它的返回值收集成数组和exec是一样的返回,都是match匹配到非g模式时的返回值。
let str = "abcde abcde abcd"; const Aregexp = /(abc)d(e)/g; const Bregexp = /(abc)d(e)/; console.log(str.match(Aregexp)); //? [abcde abcde] console.log(str.match(Bregexp)); //? [abcde abc e] console.log(Aregexp.exec(str)); //? [abcde abc e] console.log(Aregexp.exec(str)); //? [abcde abc e] console.log(Aregexp.exec(str)); //? null console.log(Bregexp.exec(str)); //? [abcde abc e] console.log(Bregexp.exec(str)); //? [abcde abc e] console.log(...str.matchAll(Aregexp)); //? [abcde abc e] [abcde abc e] console.log(...str.matchAll(Bregexp)); //! error 只能匹配g模式
(?:x)
非捕获括号这与正则的匹配无关,遇到的时候可以直接忽略该符号,直接用里面的字符与后面的拼接。
let str = "abcdbd"; const Aregexp = /(?:abc)d/; const Bregexp = /abcd/; console.log(str.replace(Aregexp, "")); //? bd console.log(str.replace(Bregexp, "")); //? bd
两个结果是一样的。
但是匹配的结果是不同的,被(?:)
括起来的不会被exec、match单独匹配出来:
let str = "abcdb"; const Aregexp = /(?:abc)(d)b/; const Bregexp = /(abc)(d)b/; console.log(Aregexp.exec(str)); //? abcdb b console.log(Bregexp.exec(str)); //? abcdb abc d
这个符号是括号的一种特殊形式,一般的括号括起来组成的组会被以$n
的形式记录,方便使用,但是用这个符号括起来的组不会被记录:
let str = "abcdbd"; const Aregexp = /(?:abc)(d)b\1/; //! `\x`会被认为是第x个括号里的内容 这里相当于\abcdbabc\ const Bregexp = /(abc)(d)b\1/; //! 这里相当于\abcdbabc\ console.log(str.replace(Aregexp, "")); //? 空 都替换掉了 因为`(?:)`不会被记录 console.log(str.replace(Bregexp, "")); //? abcdbd let strs = "abcdbabc"; console.log(strs.replace(Bregexp, "")); //? 空 都替换掉了 //! 同理 replace 中的 $x也不会记录 console.log(str.replace(Aregexp, "$2 $1")); //? $2 d console.log(strs.replace(Bregexp, "$2 $1")); //? d abc
(?<name>)
具名组匹配符这个符号和上面的(?:)
一样是括号的特殊修饰符,它会在匹配结果中生成一个groups
属性,用对象的键值对来记录括号里匹配的结果:
let str = "abcdb"; const Aregexp = /(?<first>abc)(?<secend>d)/; console.log(Aregexp.exec(str)); /* groups:{ first:"abc", secend:"d", } */
这个匹配形式在需要替换多个可能字符时很有用。
先看看replace
的第二个参数,它可以接收一个回调函数,该函数的返回值是每个匹配项被替换的字符串:
let str = "abcdb" const Bregexp = /abc/; console.log( str.replace(Bregexp, () => { return ""; }) ); //? bd
这个函数接收的参数有多个,详见MDN,可以使用解构操作符将groups取出:
let str = "abcabcdb"; const Aregexp = /(?<first>abc)|(?<secend>d)/g; const result = str.replace(Aregexp, (...arg) => { const groups = JSON.parse(JSON.stringify(arg.pop())); //! 这样可以删除没有匹配到的空属性 if (groups.first) { return "zzz"; } else if (groups.secend) { return "ddd"; } }); console.log(result); //? zzzzzzdddb