使用正则发现的一个小问题
先上代码
let str = 'abcdef'
let reg = /abc/g // 查找所有匹配项
console.log(reg.test(str)) // 输出true
console.log(reg.test(str)) // 输出false
以上代码为一段简单正则验证,验证目标字符串是否包含abc,那为什么连续两次相同的验证却得到不一样的结果呢
导致此问题的重点在于lastIndex属性
语法
RegExpObject.lastIndex
属性说明
该属性存放一个整数,它声明的是上一次匹配文本之后的第一个字符的位置。
上次匹配的结果是由方法
RegExp.exec()和RegExp.test()找到的,它们都以lastIndex属性所指的位置作为下次检索的起始点。这样,就可以通过反复调用这两个方法来遍历一个字符串中的所有匹配文本。该属性是可读可写的。只要目标字符串的下一次搜索开始,就可以对它进行设置。当方法
exec()或test()再也找不到可以匹配的文本时,它们会自动把lastIndex属性重置为0。
重要事项:不具有标志g和不表示全局模式的RegExp对象不能使用lastIndex属性。
上述对 lastIndex 做出了解释。
简单的说就是,lastIndex 默认是0,每次进行RegExp.test() 或者RegExp.exec() 操作都会对 lastIndex 进行修改。
下面看一段代码
let str = 'abcdefabc'
let reg = /abc/g // 查找所有匹配项
console.log(reg.lastIndex) // 输出 0
console.log(reg.test(str), reg.lastIndex) // 输出true 3
console.log(reg.test(str), reg.lastIndex) // 输出true 9
console.log(reg.test(str), reg.lastIndex) // 输出false 0
从代码可以看出,执行
test()方法的时候,lastIndex被改变。并且当第一次匹配到满足条件的部分时,输出
true且将lastIndex修改为3,第二次执行
test(),就是从目标字符串的第3个位置开始执行,再次匹配出满足条件的部分时,会输出true且再一次修改lastIndex。当第三次再执行
test()时,便是从目标字符串的第9个位置开始,没有匹配到对应的满足条件则返回了true,并且重新修改lastIndex为0。
以上我们可以得出结论,test() 会改变 lastIndex,并且每次匹配都是从 目标的第 lastIndex 位置开始。当匹配不到符合条件的部分时,就返回 false,lastIndex 重新设置为 0。
如何去完善这个小毛病
1、正则中可以 去掉 g ,这样便不会全匹配。
重要事项:不具有标志
g和不表示全局模式的RegExp对象不能使用lastIndex属性。
let str = 'abcdef'
let reg = /abc/ // 去掉g修饰符
console.log(reg.lastIndex) // 输出 0
console.log(reg.test(str), reg.lastIndex) // 输出true 0
如上述代码可见,正则中去掉 g 修饰符之后,便不会再影响 lastIndex。
2、不去掉 g修饰符,再执行完test() 或者 exec() 之后,对 lastIndex 进行手动赋值。
重要事项:
lastIndex属性是该属性是可读可写的。
let str = 'abcdef'
let reg = /abc/g // 没有去掉g修饰符
console.log(reg.lastIndex) // 输出 0
console.log(reg.test(str), reg.lastIndex) // 输出true 3
reg.lastIndex = 0 // 重新赋值为0
console.log(reg.test(str)) // 输出true
如上述代码可见,在执行一次 test() 之后,手动给 lastIndex 赋值为0, 再执行 test() 时就会输出我们期望得到的 true。
如你所见,非~常好用。
以上,结束吧。期待下次