正则捕获的 懒惰性
正则捕获的懒惰性
- 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"]