Reg中的lastIndex

问题出现

在写一个搜索算法测试的时候,遇到一个问题,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var search = function(data,text){
var arr = text.split(''),reg='[A-z]*';
for(var i in arr){
reg = reg + arr[i] + '[A-z]*'
}
var _regExp =new RegExp(reg,'gi');
for(var j in data){
if(_regExp.test(data[j])){
console.log(data[j]);
}
}
}

search(['yreenchan','alenwang','maginazhang'],'ea');

当我自信地觉得输出结果应该是yreenchan、alenwang的时候,结果现实给了我一个啪啪啪的耳光,输出结果只有yreenchan,百思不得其解。然后我把第二个跟第三个元素调换了一下位置,数组变成[‘yreenchan’,’maginazhang’,’alenwang’]的时候,奇迹的事情出现了,结果就是我们所期望的yreenchan、alenwang,对此,我不禁开始怀疑起了人生。

lastIndex

当我去搜索Reg的test用法的时候,我发现了一个叫lastIndex的家伙。lastIndex 属性用于规定下次匹配的起始位置。就是说,当我们使用全局搜索的时候,test会记录当前匹配的位置,然后下一次调用test的时候就会从lastIndex这个位置继续匹配。当我原因为每一个for循环会重置的时候,才发现当初设置的全局匹配并不会因为for循环而从头开始匹配,而是根据lastIndex继续搜索。

原因分析

但是为什么改成[‘yreenchan’,’maginazhang’,’alenwang’]就有正确结果输出了呢?那是因为lastIndex还有一个特点,就是当它匹配失败的时候,lastIndex会重置为0。也就是说,匹配yreenchan的时候,匹配成功,lastIndex设置为9,然后从maginazhang的第9个字符开始匹配,发现匹配失败,lastIndex重置为0,然后从alenwang的开头开始匹配,发现匹配成功,所以结果就是我们预期的yreenchan、alenwang。对于初始数组[‘yreenchan’,’alenwang’,’maginazhang’]来说,当匹配第一个yreenchan的时候,lastIndex设置为9,然后从alenwang的第9个字符开始匹配,alenwang本身只有8个字符,所以第9个字符当然匹配失败了,这时候lastIndex重置为0,然后从maginazhang的开头开始匹配,还是匹配失败,所以结果只有yreenchan。

解决方法

1、每次搜索完重置lastIndex,将for循环体改成如下:

1
2
3
4
5
6
for(var j in data){
if(_regExp.test(data[j])){
_regExp.lastIndex = 0;
console.log(data[j]);
}
}

2、去除全局匹配g
3、使用match代替test进行正则匹配