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

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

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

情景回放

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

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因为判断多执行一次。



这下就完全匹配了。

小爬虫完整代码:见哲理

说说正则表达式的exec方法的更多相关文章

  1. js正则表达式test方法、exec方法与字符串search方法区别

    1.正则表达式test方法 test() 方法用于检测一个字符串是否匹配某个模式 返回值: 如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 fal ...

  2. 正则表达式exec方法的陷阱

    http://www.w3school.com.cn/jsref/jsref_exec_regexp.asp exec() 方法的功能非常强大,它是一个通用的方法,而且使用起来也比 test() 方法 ...

  3. js进阶正则表达式13RegExp对象方法(RegExp对象的方法:compile,test,exec)(子表达式 var reg1=/([a-z]+)\d/)

    js进阶正则表达式13RegExp对象方法(RegExp对象的方法:compile,test,exec)(子表达式 var reg1=/([a-z]+)\d/) 一.总结 1.RegExp对象有三个方 ...

  4. JavaScript中String的math方法与RegExp的exec方法的区别

    1.exec是正则表达式的方法,方法参数为字符串.match为字符串的方法,参数为正则表达式对象. 2.match与exec都返回数组.如果调用exec方法的正则表达式没有分组内容,则返回第一个匹配的 ...

  5. exec方法

    如果 exec 方法没有找到匹配,将返回 null.如果找到匹配项,则 exec 方法返回一个数组,并将更新全局 RegExp 对象的属性以反映匹配结果.数组元素 0 包含了完整的匹配项,而元素 1 ...

  6. javascript exec方法

    题目 取出 "[大哭][尴尬][发怒][发怒][调皮][调皮][呲牙]" 串中[]里面的东西 思路 正则匹配,/\[(.+?)\]/ig; exec方法循环 exec() 方法的功 ...

  7. JavaScript:exec()方法的用法及说明

    最近在看某知名js框架的源码,突然间发现自己对exec()方法竟然不太理解,然后就仔细的分析了一下这个方法 下面贴个exec()方法使用的代码出来 rquickExpr = /^(?:\s*(< ...

  8. JavaScript RegExp对象的exec()方法

    JavaScript RegExp对象的exec()方法用来匹配字符串,它的行为与match()有些不同. 对于RegExpObject.exec(),w3school上面是这样介绍的: exec() ...

  9. JavaScript RegExp.exec() 方法

    定义和用法: exec() 方法用于检索字符串中的正则表达式的匹配. 语法: RegExpObject.exec(string); RegExpObject:必须参数,正则表达式: string:必须 ...

随机推荐

  1. 【慕课网实战】Spark Streaming实时流处理项目实战笔记九之铭文升级版

    铭文一级: 核心概念:StreamingContext def this(sparkContext: SparkContext, batchDuration: Duration) = { this(s ...

  2. 巧用NULL模式解耦依赖

    1. 初始 应用A和应用B均用到了库libX.a中的类class A: 由于需求的变化,应用B需要库libM.a的能力,以便和服务M交互.为了复用和简化,通过类A间接提供,应用B不用修改代码,只需要重 ...

  3. 1.8.2suspend与resume方法的缺点-独占

    这两个方法使用不当,容易造成公共的同步对象的独占,使得其他线程无法访问公共的同步对象 测试 package com.cky.bean; /** * Created by edison on 2017/ ...

  4. Swift3翻天覆地的改变

    经历了从swift 1.0 到2.0,一个版本之后代码居然就不兼容了.这如何在团队推广呢?没有想到3.0居然变化更加的大.有多大,来体会一下: UIFont.preferredFontForTextS ...

  5. 使用Kotlin&Anko, 扔掉XML开发Android应用

    尝鲜使用Kotlin写了一段时间Android.说大幅度的减少了Java代码一点不夸张.用Java的时候动不动就new一个OnClickListener()匿名类,动不动就类型转换的地方都可以省下很多 ...

  6. Beta阶段第二篇Scrum冲刺博客-Day1

    1.站立式会议 提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 张晨晨:交接进组 郭琪容:明确任务并学习 吴玲:明确接 ...

  7. C语言中:static与extern对变量和函数的作用

    1.两者对全局变量 static对全局变量,表示定义一个内部变量 extern对全局变量,表示声明一个外部变量 说明: 1.内部变量:定义的变量只能在本文件中访问,不能被其他文件访问. 2.不同文件中 ...

  8. 《mysql必知必会》学习_第13章_20180803_欢

    第13章:分组过滤. P83 select count(*) as num_prods from products where vend_id=1003; #返回vend_id=1003的产品数目总值 ...

  9. 微信小程序-bindtap事件与冒泡

    bindtap就是点击事件 在.wxml文件绑定: <text id='textId' data-userXxx='100' bindtap='tapMessage'>cilck here ...

  10. Eclipse新建工作空间,复制原有的配置

    步骤一: File->Switch workspace->Other...,按下图选择 只复制简单的配置,如cvs之类的信息是不会复制的.     步骤二: 在方法一的基础上做如下操作  ...