在 Javascript 中使用 exec 进行正则表达式全局匹配时,有一个非常容易犯的错误,这是因为 exec() 在全局模式下的行为稍微有点复杂。本文就是介绍在使用 Javascript 中使用 exec 进行正则表达式全局匹配时的注意事项。
先看一下常见的用法:
<script type="text/javascript"> var pattern = /http://([^/s]+)/; alert(pattern.exec('http://www.codebit.cn')); // http://www.codebit.cn,www.codebit.cn alert(pattern.exec('http://YITU.org')); // http://YITU.org,YITU.org // 也可以直接写成 /http://([^/]+)/.exec('http://www.codebit.cn'); </script>
接下来看一下全局模式下的诡异事件:
<script type="text/javascript"> var pattern = /http://([^/s]+)/g; // 使用了 g 修饰符 alert(pattern.exec('http://www.codebit.cn')); // http://www.codebit.cn,www.codebit.cn alert(pattern.exec('http://YITU.org')); // 并没有返回期望的 http://YITU.org,YITU.org ,而是返回了 null </script>
第二个语句并没有返回期望的结果,而是返回了 null ,这是因为:
在全局模式下,当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把正则表达式对象的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。
下面是正常的全局模式下的匹配方式:
<script type="text/javascript"> var pattern = /http://([^/s]+)/g; var str = "CodeBit.cn : http://www.codebit.cn | YITU.org : http://YITU.org"; var result; while ((result = pattern.exec(str)) != null) { alert("Result : " + result + " LastIndex : " + pattern.lastIndex); } //Result : http://www.codebit.cn,www.codebit.cn LastIndex : 34 //Result : http://YITU.org,YITU.org LastIndex : 67 </script>
从上面的代码我们可以看到,之所以出现第二段代码中的问题,影响因素是 lastIndex ,所以我们可以通过将 lastIndex 手动置 0 的方式来解决这个问题。
<script type="text/javascript"> var pattern = /http://([^/s]+)/g; // 使用了 g 修饰符 alert(pattern.exec('http://www.codebit.cn')); // http://www.codebit.cn,www.codebit.cn pattern.lastIndex = 0; alert(pattern.exec('http://YITU.org')); // http://YITU.org,YITU.org </script>
总结:
在全局模式下,如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串,就必须手动地把 lastIndex 属性重置为 0。
懒人的做法经常是用比较流氓的, 来个一劳永逸的办法:
if( ! RegExp.prototype.exec_ori ){
/**
* 修正同一个正则对不同字串进行处理时不会自动清除lastIndex的错误
*/
RegExp.prototype.exec_ori = RegExp.prototype.exec;
RegExp.prototype.exec_cache;
RegExp.prototype.exec = function (string){
if(RegExp.prototype.exec_cache != string){
RegExp.prototype.exec_cache = string;
this.lastIndex=0;
}
return this.exec_ori(string);
};
}
这种方式的确高明,通过判断是否执行的是同一个正则来决定是否将 lastIndex 置为 0,既解决了问题又保留了全局匹配的默认行为,佩服!