基于正则exec方法封装一个可以匹配所有的符合规则的方法

258 阅读2分钟

正则方法 exec()

  1. 正则中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
    
  2. 设置全局修饰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  然后就会从开始的重新匹配
    
  3. 所以,基于上面的结果,封装一个使用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))
    
  4. 解释说明:

    • 在execAll函数中,因为是正则的实例调用该函数,所以,execAll方法中的this指向的是正则实例,所以,this就是正则规则的表达式
    • 在正则对象的属性中,有global属性,描述的是是否是全局匹配,如果是全局匹配,才会循环,不是,则直接返回exec方法匹配的结果
    • 为了让execAll函数返回的结果保持一致,所以做了这个判断arr.length ? arr : null(因为RegExp.prototype.exec如果匹配不到符合的内容时,会返回null)
  5. 总结:
    使用字符串的String.prototype.match方法,一次匹配所有符合正则规则,它不香吗?