先来看看这么一段代码,用来查找以"hanyu"为拼音的汉字及其拼音构成的字符串:
1 var xds = "{汉字,hanzi%hz},{标签,biaoqian%bq},{汉语,hanyu%hy},{韩语,hanyu%hy},{汗水,hanshui%hs},{彪悍,biaohan%biaohan},{cd, ef, jh, abc, edf, abdc,cd, abcd, abxd}";
2 var regx = new RegExp("{[\u4e00-\u9fa5]*,((hanyu[a-z]*%[a-z]+)|([a-z]+%hanyu[a-z]*))}");
3 var result;
4 var str = "";
5 while ( (result = regx.exec(xds)) != null ) {
6 str = [str, result[0]].join(" ");
7 xds = xds.substring(regx.lastIndex);
8 }
2 var regx = new RegExp("{[\u4e00-\u9fa5]*,((hanyu[a-z]*%[a-z]+)|([a-z]+%hanyu[a-z]*))}");
3 var result;
4 var str = "";
5 while ( (result = regx.exec(xds)) != null ) {
6 str = [str, result[0]].join(" ");
7 xds = xds.substring(regx.lastIndex);
8 }
这段代码在IE系列(目前测了IE8及以下的浏览器)能够正常运行,得到期望的结果,在ff/chrome执行会导致浏览器崩溃。
根源在哪?
问题出在regx.lastIndex上,上述代码中正则表达式没有设置任何标识位,在匹配到第一个结果后就停了下来。IE中执行regx.exec()后,regx.lastIndex会被设置成上次匹配成功的位置,但ff/chrome不会。在ff/chrome中,第一次匹配结束后,lastIndex值不会被修改,始终为初始值0。
知道问题所在后,给正则表达式增加global标识,做全局匹配。修改后的代码:
1 var xds = "{汉字,hanzi%hz},{标签,biaoqian%bq},{汉语,hanyu%hy},{韩语,hanyu%hy},{汗水,hanshui%hs},{彪悍,biaohan%biaohan},{cd, ef, jh, abc, edf, abdc,cd, abcd, abxd}";
2 var regx = new RegExp("{[\u4e00-\u9fa5]*,((hanyu[a-z]*%[a-z]+)|([a-z]+%hanyu[a-z]*))}", "g");
3 var result;
4 var str = "";
5 while ( (result = regx.exec(xds)) != null ) {
6 str = [str, result[0]].join(" ");
7 }
2 var regx = new RegExp("{[\u4e00-\u9fa5]*,((hanyu[a-z]*%[a-z]+)|([a-z]+%hanyu[a-z]*))}", "g");
3 var result;
4 var str = "";
5 while ( (result = regx.exec(xds)) != null ) {
6 str = [str, result[0]].join(" ");
7 }
当使用g时,表示进行全局匹配,而不是第一次匹配成功后停下来,待查找的字符串中所有匹配的字符串都应该被找到。执行exec后,regx的lastIndex属性将被修改成上一次匹配成功的字符串最后一个字符所在的位置,下一次执行时,将从lastIndex处的字符开始查找。
也许你会怀疑是不是IE中,正则表达式默认使用了全局匹配,而ff/chrome没有。其实不是,ie没有这么做。如果怀疑,可将代码这么修改一下 :
var regx = new RegExp("{[\u4e00-\u9fa5]*,((hanyu[a-z]*%[a-z]+)|([a-z]+%hanyu[a-z]*))}");
执行后就会发现ie也进入无响应状态(cpu使用率100%)。证明IE并没有去默认做全局匹配。