正则表达式共享问题

票务监控 的一个应用:高亮原页面关注城市名,原来做法为对每条记录的innerhtml都进行

 

var reg=/郑州/g;
el.innerHTML=el.innerHTML.replace(reg,"....");
 

想优化一下,避免不必要的DOM操作,同时共享一个正则实例:

 

var reg=/郑州/g;
if(reg.test(el.innerHTML))
el.innerHTML=el.innerHTML.replace(reg,"....");
 

结果出现了意想不到的结果,抽象如下:


例子:

 

猜猜下面代码内容:

 

var reg=/a/g;
console.log(reg.test('a'));
//console.log(reg.lastIndex); 
console.log(reg.test('a'));
//console.log(reg.lastIndex); 

 

吃惊的话看看下面:

 

var reg=/a/g;
console.log(reg.test('a'));
//console.log(reg.lastIndex); 
console.log(reg.test('ba'));
//console.log(reg.lastIndex); 
 

还是要看规范:


15.10.6.3 RegExp.prototype.test(string)
The following steps are taken:
1.  Let match be the result of evaluating the RegExp.prototype.exec (15.10.6.3) algorithm upon this
RegExp object using string as the argument.
2.  If match is not null, then return true; else return false.


我一直忽略了原来 test 实际上是 :


(r.exec(s) != null)


那么知道exec 对待 g 正则表达式,会记录 lastIndex 到这个正则表达式上,这样子的话 第二个 test 则会从第一个 test 的 lastIndex 开始匹配,出现了上述的结果。

 

总结原因:


1.test 等于 调用exec

2.lastIndex 存在于正则表达式中,而不是 java 一样有一个 matcher 对象存放 index,或者像 perl 一样 lastIndex 实际上和字符串关联,而javascript 这样子lastIndex和正则表达式关联,test还是最好不要设 g。

3.不成熟的优化等于魔鬼,实际上我可以再单独设一个检测正则表示式即可:


var reg=/郑州/g;
var reg2=/郑州/;
if(reg2.test(el.innerHTML))
  el.innerHTML=el.innerHTML.replace(reg,"....");
 

PS:共享带来的问题:

 

有时想为了一点内存,共享几个对象实例,而对于正则表达式则要特别小心,因为正则实例的一些状态比如lastIndex在不同的操作中(test,exec)常常会被影响的,例如:

 

    var script_re = /x/g;
    var m,x = "avbxz",loop = 1;

    while (m = script_re.exec(x)) {
        console.log(script_re.lastIndex + " : " + m[0]);
        //重置lastIndex要死循环喽
        //"y".replace(script_re, "");
        //console.log("after replace : "+script_re.lastIndex );
        //"y".match(script_re);
        //console.log("after match : "+script_re.lastIndex );

        loop++;
        if (loop == 100) {
            alert("die!");
            break;
        }
    }
 

 

updated : 2010-12-10

 

用 match 取代 test

 

最好还是不要用 test 来进行判断 :

 

var reg=/d/g;
console.log(reg.test("dd"));
console.log(reg.test("dg"));

 

因为 test 在 //g 会导致lastIndex 记载在该正则表达式中影响后续操作,如果不在乎性能的话,可用 match 取代:

 

var reg=/d/g;
console.log("dd".match(reg));
console.log("dg".match(reg));
 

 

 

 

你可能感兴趣的:(JavaScript,正则表达式,prototype,perl)