正则方法 exec()
-
正则中RegExp.prototype.exec方法,在匹配到符合正则规则的内容时,如果没有设置全局修饰符g,则只会匹配到第一项符合规则的内容(原因是:这个时候RegExp.lastIndex没有被修改,还是0)
let reg = /\d+/ console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex) // 0 console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex) // 0 console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex)// 0 console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex)// 0 console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex) // 0 -
设置全局修饰g之后,每次调用RegExp.prototype.exec()时,都会修改RegExp.lastIndex的值,修改为符合规则内容的下一项,作为匹配的起始位置,如果全部匹配完之后,再次调用RegExp.prototype.exec()匹配,得到的结果为null,此时的lastIndex变成了0,也就意味着下一次,调用正则的exec方法,则是从字符串的起始位置开始匹配
let str = 'zhangsan2019zhangsan2020zhangsan2021' let reg = /\d+/g console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex) // 12 console.log(reg.exec(str)) // ["2020", index: 20, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex)// 24 console.log(reg.exec(str)) // ["2021", index: 32, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex)// 36 console.log(reg.exec(str)) // null 全部匹配结果之后,再次匹配结果为null, lastIndex变成 0,再次捕获,就会重新开始 console.log(reg.lastIndex)// 0 console.log(reg.exec(str)) // ["2019", index: 8, input: "zhangsan2019zhangsan2020zhangsan2021", groups: undefined] console.log(reg.lastIndex) // 12 然后就会从开始的重新匹配 -
所以,基于上面的结果,封装一个使用RegExp.prototype.exec()一次就可以匹配所有的符合正则规则的内容
(function(){ function execAll (str = '') { // 在调用时,该函数中的this指向的是RegExp的实例,所以正则表达式就是this // 这是全局匹配的情况下,如果不是全局,则会 进入一个死循环 // console.dir(this) if (!this.global) return this.exec(str) let arr = [], res = this.exec(str) while (res) { arr.push(res[0]) res = this.exec(str) } return arr.length ? arr : null } RegExp.prototype.execAll = execAll })() let str = 'zhangsan2019zhangsan2020zhangsan2021' let reg = /\d+/g console.log(reg.execAll(str)) -
解释说明:
- 在execAll函数中,因为是正则的实例调用该函数,所以,execAll方法中的this指向的是正则实例,所以,this就是正则规则的表达式
- 在正则对象的属性中,有global属性,描述的是是否是全局匹配,如果是全局匹配,才会循环,不是,则直接返回exec方法匹配的结果
- 为了让execAll函数返回的结果保持一致,所以做了这个判断arr.length ? arr : null(因为RegExp.prototype.exec如果匹配不到符合的内容时,会返回null)
-
总结:
使用字符串的String.prototype.match方法,一次匹配所有符合正则规则,它不香吗?