阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      正则捕获的 懒惰性

      正则捕获的懒惰性

      • exec 每执行一次,只能捕获到一个符合规则的内容;
      • 默认状态下,无论我们执行多少次,都只能捕获到第一个匹配的数据,其余的捕获不到
      • 默认情况下,只能捕获到第一个数据,这种现象叫正则的懒惰性;

      reg.lastIndex

      reg.lastIndex 表示当前正则下一次匹配的起始索引位置;

      let str = "axihe2020an06bang30";
      let reg = /\d+/;
      console.log(reg.lastIndex);//0
      console.log(reg.exec(str));//true
      console.log(reg.lastIndex);//0
      console.log(reg.exec(str));//true
      

      第一次匹配捕获完成,lastIndex 没有改变,所以下一次 exec 依然输从字符串最开始查找,找的永远都是第一个匹配到的数据。

      正则的懒惰性的原因

      正则的懒惰性的原因:默认情况下,lastIndex 的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远都是第一个内容。

      下面我们尝试手动修改 lastIndex, 发现改不了。

      let str = "axihe2020an06bang30";
      let reg = /\d+/;
      console.log(reg.lastIndex);//0
      console.log(reg.exec(str));//true
      reg.lastIndex = 11
      console.log(reg.lastIndex);//0
      console.log(reg.exec(str));//true
      

      修饰符g可以解决正则懒惰性

      let str = "axihe2020an06bang30";
      let reg = /\d+/g;
      console.log(reg.lastIndex);//0
      console.log(reg.exec(str));//["2020", index: 5, input: "axihe2020an06bang30", groups: undefined]
      console.log(reg.lastIndex);//9
      console.log(reg.exec(str));//["06", index: 11, input: "axihe2020an06bang30", groups: undefined]
      console.log(reg.lastIndex);//13
      console.log(reg.exec(str));//["30", index: 17, input: "axihe2020an06bang30", groups: undefined]
      console.log(reg.lastIndex);//19
      console.log(reg.exec(str));//null
      

      我们总结一下

      • 修饰符g可以解决正则懒惰性的核心是:g可以更改lastIndex
      • 当全局捕获都已完成以后,再次捕获的结果是 null;
      • lastIndex 再捕获结果为 null 的时候回归到初始值 0,如果再进行捕获就开始循环啦;

      test 方法可以打破正则懒惰性

      let str = "axihe2020an06bang30";
      let reg = /\d+/g;
      //验证:只有正则和字符串匹配我们再捕获
      if (reg.test(str)) {
          console.log(reg.lastIndex);//9
          console.log(reg.exec(str));//["06", index: 11, input: "axihe2020an06bang30", groups: undefined]
          console.log(reg.test(str));//true
          console.log(reg.lastIndex);//19
      }
      

      我们总结:

      • test 可以把 lastIndex 修改
      • test 改为当前匹配后的结果(下次匹配不再是预期的位置了)

      编写 execAll 方法

      编写 execAll 方法,执行一次可以把所有匹配的结果捕获到,前提正则一定要设置全局修饰符;

      如何验证一个正则是否设置了修饰符g

      let reg = /\d+/g;
      console.dir(reg)
      

      输出结果

      dotAll: false
      flags: "g"
      global: true
      ignoreCase: false
      lastIndex: 0
      multiline: (...)
      source: (...)
      sticky: (...)
      unicode: (...)
      __proto__: Object
      

      可以通过 reg.global 是否为 true 判断正则的修饰符;

      如何写execAll

      
      let str = "axihe2020an06bang30";
      (() => {
          // execAll 参数str : 要匹配的字符
          // execAll 中的this: RegExp的实例(当前操作的正则)
          // 注意` function (str = "")`不能用箭头函数
          RegExp.prototype.execAll = function (str = "") {
              let ary = [],
                  res = this.exec(str);//每次捕获到的内容
      
              if (!this.global) {
                  return res;
              }
              // 只要捕获的不为null
              while (res) {
                  ary.push(res[0])
                  res = this.exec(str);
              }
              return ary.length ? ary : null;
          }
      })()
      let reg = /\d+/g;
      console.dir(reg);//可以在`__proto__`上看到execAll方法
      console.log(reg.execAll(str));//["2020", "06", "30"]
      console.log(reg.execAll('axihe.com'));//null
      

      match是打破正则懒惰性的最优解

      字符串的match方法,可以在执行一次的情况下,捕获到所有匹配的数据;

      前提:正则也需要设置修饰符g;

      let str = "axihe2020an06bang30";
      let reg1 = /\d+/;
      let reg2 = /\d+/g;
      console.log(str.match(reg1));//["2020", index: 5, input: "axihe2020an06bang30", groups: undefined]
      console.log(str.match(reg2));// ["2020", "06", "30"]
      
      目录
      目录