JavaScript RegExp 正则表达式g模式的使用

说明下, 文章中的有些东西来自Franky大神的文章<浏览器中的 正则表达式陷阱>.

试考虑如下代码:

var re = /^\w$/g;
re.test(‘a’); //返回true
re.test(‘b’); //还是true吗?

猜猜返回值都是什么呢? 如果你已经阅读了Franky大神的那篇文章, 或者自己动手试了下, 就会发现, 一次是true, 一次是false. 原因在于正则表达式中的g, 使得搜索过程后, 如果匹配成功, 则记录上一次的位置, 如果匹配不成功, 则会归零. 所以, 如果在上面的语句中再加一条re.test(‘s’), 那么返回的将又会是我们期望的true了.

不过一般情况下, 我们自然会希望得到同样的结果, 这个时候可以在其中添加一条语句, 人工将位置归零, 防止这个 “错误” 的发生:

var re = /^\w$/g;
re.test(‘a’); //返回true
re.lastIndex = 0; //归零搜索的位置
re.test(‘b’); //返回true

或者我们可以更简单地直接将g去掉:

var re = /^\w$/;
re.test(‘a’); //返回true
re.test(‘b’); //返回true

于是, 利用g模式的这个性质, 可以这样使用. 考虑下面的代码:

var re = /\w/g; //注意, 我将分别表示开头的^和$去掉了
re.test(‘ab’);
re.test(‘ab’);

猜猜现在会返回什么呢? 答案是两个true. 用之前说到的东西也很好解释, 因为第一次记录了一个lastIndex, 但是在这个lastIndex的情况下, 同样能匹配成功第二个. 也就是说, 第一次匹配的是字符串中的a字母, 第二次则是b字母. 我在这里刻意地使用了两个相同的字符串, 因为我想告诉大家, 这才是g模式下, 正确的用法. 下面我们继续讨论这种机制存在的意义, 我也直接切入要害. 考虑下面的代码:

var re = /\d+/g;
var str = ‘1## %$xx 34*&920 3’; //包含了数字的字符串

var arr = [];

while (re.test(str))
    arr.push(RegExp.lastMatch);
/*
    上面的代码我更愿意写成:
    var parts;
    while (parts = re.exec(str))
        arr.push(parts[0]);
    这样可以避免全局的RegExp对象造成的一些问题.
*/

alert(arr); //”1,34,920,3″

点到这里, 相信大家已经初步明白这种机制的用意了,它方便自定义的遍历 (当lastIndex已经达到字符串末尾时, 并不归零), 要知道, 在明白这点之前, 我一直用着replace来完成这一步. 现在, 大家可以用自己的循环来搞定了. 这种情况也提醒了我们, 要正确地使用g参数, 像前面那种正则中包含^或者$的加上g参数, 就是完全的画蛇添足, 这些是应当避免的.

当然, 以上也只是Vilic的个人认识, 欢迎大家指正!