说说正则表达式的exec方法

话说,关于正则表达式有一个梗,大意是:

假如你有一个问题,想用正则来解决,于是你就有了两个问题

这句话侧面反映了精通正则是一件不容易的事。比如我今天遇到的诡异事件。

情景回放

这两天练手写了一个爬用户在博客园所有文章阅读量的简单爬虫。可以输出某用户的随笔总阅读量。如在命令行输入:

node index imgss

得到总阅读量是3602.

地址在readcounter;

其中有这么一段代码:

var re = /阅读\((\d+)\)/g;
 while(true) {
                        if(!re.exec(html))//第一次调用
                             break; //此处会浪费一次re匹配,导致第一个匹配到的从第二个开始。
                        var match = re.exec(html)[1]; //第二次调用。匹配阅读量数据
                            console.log(match);
                    }

现在假设html是下面的字符串

var html=`posted @ 2017-03-17 22:32 nobody-junior 阅读(12) 评论(0)  编辑posted @ 2017-03-05 22:55 nobody-junior 阅读(29) 评论(0)  编辑posted @ 201
7-03-02 22:28 nobody-junior 阅读(588) 评论(4)  编辑posted @ 2017-02-23 18:38 nobody-junior 阅读(58) 评论(0)  编辑posted @ 2017-02-20 21:
52 nobody-junior 阅读(5) 评论(0)  编辑posted @ 2017-02-18 23:19 nobody-junior 阅读(16) 评论(0)  编辑posted @ 2017-02-14 18:45 nobody-jun
ior 阅读(9) 评论(0)  编辑posted @ 2017-02-11 20:24 nobody-junior 阅读(7) 评论(0)  编辑posted @ 2017-01-18 23:16 nobody-junior 阅读(125)
评论(0)  编辑posted @ 2017-01-06 20:38 nobody-junior 阅读(208) 评论(0)  编辑`;

运行的结果如下:

也就是跳过第一个12,匹配了29,然后跳过588,匹配到58

原因分析

没有理解re.exec的用法。阮大的文章说的很详细RegExp对象;

exec方法返回的是一个数组:比如这里返回的:

数组的第一项是匹配到的字符串,这里是阅读(12),
第二项是re中用()括起来的部分,这里是12,
第三项是原始字符串,这里是html.

以上面的为例:re=/阅读\((\d+)\)/g,用来匹配字符串中的“阅读()“部分。

在上面的while循环中,调用了两次exec方法。一次是为了判断匹配是否结束,匹配到之后,这里是”阅读(12)“没有对方法的返回值进行处理,直接进行了下一次调用。

再次调用的时候,就会跳到下一次匹配到的地方,这里是'阅读(29)',所以出现了只匹配偶数的情况。

解决

将循环部分的代码改一下:

                    while(true) {
                        var match = re.exec(html); //匹配阅读量数据

                        if(match)
                            console.log(match[1]);
                        else
                            break;
                    }

这样将每次exec方法的返回值赋值给match变量。然后对match进行匹配,不会让exec因为判断多执行一次。


这下就完全匹配了。

小爬虫完整代码:见哲理

posted @ 2017-03-26 12:06  饭特稠  阅读(938)  评论(0编辑  收藏  举报