1. 实现正则捕获的办法


1. 正则RegExp.prototype上的方法

  • exec
  • test

2. 字符串String.prototype上支持正则表达式处理的方法

  • replace
  • match
  • splite
  • .......

2. 实现正则的前提


当前正则要和字符串匹配,如果不匹配捕获的结果是null

let reg = /^\d+$/;
let str = "JavaScript2020JavaScript2020";
console.log(reg.test(str)); //=>false
console.log(reg.exec(str)); //=>null

3. 正则捕获的懒惰性


let reg = /\d+/;
let str = "JavaScript2020JavaScript2020";/** 基于exec实现正则的捕获*   1.捕获到的结果是null或者一个数组*     第一项:本次捕获到的内容*     其余项:对应小分组本次单独捕获的内容*     index:当前捕获内容在字符串中的起始索引*     input:原始字符串*   2.每执行一次exec,只能捕获到一个符合正则规则的,但是默认情况下,我们执行一百遍,获取的结果永远都是第一个匹配到的,其余的捕获不到*     =>“正则捕获的懒惰性”:默认只捕获第一个*/
console.log(reg.exec(str)); //=>["2020", index: 7, input: "JavaScript2020JavaScript2020"]
console.log(reg.exec(str)); //=>["2020"...]

4. 捕获懒惰性的解决办法


4.1 利用 reg.lastIndex 找到捕获懒惰性的原因

/** reg.lastIndex:当前正则下一次匹配的起始索引位置 *   懒惰性捕获的原因:默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远只是第一个*   解决办法:全局修饰符g*/
let reg = /\d+/;
let str = "JavaScript2019JavaScript2020JavaScript2021";
console.log(reg.lastIndex); //=>0 下面匹配捕获是从STR索引零的位置开始找
console.log(reg.exec(str));
console.log(reg.lastIndex); //=>0 第一次匹配捕获完成,lastIndex没有改变,所以下一次exec依然是从字符串最开始找,找到的永远是第一个匹配到的

4.2 利用全局修饰符 g 解决捕获的懒惰性

let reg = /\d+/g;
let str = "JavaScript2019JavaScript2020JavaScript2021";
console.log(reg.exec(str)); //=>["2019"...]
console.log(reg.lastIndex); //=>11 设置全局匹配修饰符g后,第一次匹配完,lastIndex会自己修改
console.log(reg.exec(str)); //=>["2020"...]
console.log(reg.lastIndex); //=>22
console.log(reg.exec(str)); //=>["2021"...]
console.log(reg.lastIndex); //=>32
console.log(reg.exec(str)); //=>null 当全部捕获后,再次捕获的结果是null,但是lastIndex又回归了初始值零,再次捕获又从第一个开始了...
console.log(reg.lastIndex); //=>0
console.log(reg.exec(str)); //=>["2019"...]

4.2.1 注意一

有一个使用场景是:先验证正则和字符串是否匹配,匹配再进行捕获。这时利用全局修饰符就会出错。

// 场景:先验证正则和字符串是否匹配,匹配再进行捕获
let reg = /\d+/g;
let str = "JavaScript2019JavaScript2020JavaScript2021";
if (reg.test(str)) {console.log(reg.lastIndex); //=>11  原因:基于test匹配验证后,lastIndex已经被修改为第一次匹配后的结果,所以下一次捕获不再从头开始了console.log(reg.exec(str)); //=>["2020"...]
}

解决办法: 搞两个相同的正则规则,一个用于验证判断,一个用于捕获。

4.2.2 注意二

不能一次捕获所有匹配的结果。

解决办法见4.3

4.3 一次捕获所有匹配的结果

方法一:为RegExp.prototype添加自定义方法。

// 需求:编写一个方法execAll,执行一次可以把所有匹配的结果捕获到
// 前提:正则一定要设置全局修饰符g
~ function () {function execAll(str = "") {// str:要匹配的字符串// this:RegExp的实例(当前操作的正则)// 进来后的第一件事,是验证当前正则是否设置了g,不设置则不能在进行循环捕获了,否则会导致死循环if (!this.global) return this.exec(str);// ARY存储最后所有捕获的信息  RES存储每一次捕获的内容(数组)let ary = [],res = this.exec(str);while (res) {// 把每一次捕获的内容RES[0]存放到数组中ary.push(res[0]);// 只要捕获的内容不为NULL,则继续捕获下去res = this.exec(str);}return ary.length === 0 ? null : ary;}RegExp.prototype.execAll = execAll;
}();let reg = /\d+/g;
console.log(reg.execAll("JavaScript2019JavaScript2020")); //=> ["2019", "2020"]

方法二:字符串match方法

// 字符串中的match方法,可以在执行一次的情况下,捕获到所有匹配的数据
// 前提:正则设置g才可以
console.log("JavaScript2019JavaScript2020".match(reg)); //=> ["2019", "2020"]

5. 正则捕获的贪婪性


默认情况下,正则捕获按照最长结果来捕获。

在量词元字符后设置  ?  可以按照最短结果来捕获。

let str = "JavaScript2019JavaScript2020";//=>正则捕获的贪婪性:默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
let reg1 = /\d+/g;
console.log(str.match(reg)); //=>["2019","2020"]//=>在量词元字符后面设置 ? 可以取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)
let reg2 = /\d+?/g;
console.log(str.match(reg)); //=>["2", "0", "1", "9", "2", "0", "2", "0"]

补充知识:问号在正则中的五大作用

  1. 问号左边是非量词元字符:本身代表量词元字符,出现零到一次
  2. 问号左边是量词元字符:取消捕获时候的贪婪性
  3. (?:) 只匹配不捕获
  4. (?=) 正向预查
  5. (?!) 负向预查

6. 分组捕获


6.1 简单捕获

例:身份证号码每部分的捕获。

let str = "123456789012345678";
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;console.log(reg.exec(str));
console.log(str.match(reg));//=>输出  ["123456789012345678", "123456", "7890", "12", "34", "7", index: 0, input: "123456789012345678", groups: undefined]
//=>输出  第一项:整个正则匹配的结果
//=>输出  其余项:每一个小分组单独匹配捕获的结果
//=>如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获(即不需要展示在输出结果的Array里),可以基于?:来处理,(?:)即为只分组不捕获。例子中,最后一项即没有捕获到

6.2 复杂捕获

既要捕获到{数字},也想单独的把数字也获取到。

例1:现有字符串 str = "{0}年{1}月{2}日";     需要第一次找到 {0} 还需要单独获取0。

let str = "{0}年{1}月{2}日";// 不设置g只匹配一次,exec和match获取的结果一致(既有整个正则匹配的信息,也有小分组匹配的信息)
let reg = /\{(\d+)\}/;
console.log(reg.exec(str)); //=>["{0}", "0", index: 0, input: "{0}年{1}月{2}日", groups: undefined]
console.log(str.match(reg)); //=>["{0}", "0", index: 0, input: "{0}年{1}月{2}日", groups: undefined]

例2:现有字符串 str = "{0}年{1}月{2}日";    需要一次就找到 {0} {1}{2}还需要单独获取0,1,2。

// 多次匹配的情况下,match只能把整个正则匹配的内容获取到,小分组匹配的信息无法获取。这种办法行不通。
// 可自己验证一下
// let reg = /\{(\d+)\}/g;
// let str = "{0}年{1}月{2}日";
// console.log(str.match(reg)); //=> ["{0}", "{1}", "{2}"]// 自定义实现方法
let reg = /\{(\d+)\}/g;
let str = "{0}年{1}月{2}日";let aryBig = [],arySmall = [],res = reg.exec(str);
while(res) { // 循环push每一次捕获的结果let [big,small] = res; // 解构每一次捕获的结果aryBig.push(big);arySmall.push(small);res = reg.exec(str);
}
console.log(aryBig,arySmall); //=>["{0}", "{1}", "{2}"] ["0", "1", "2"]

补充知识:分组的第三个作用 => 分组引用

let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/; // 分组引用就是通过“\数字”让其代表和对应分组出现一模一样的内容
console.log(reg.test("book")); //=>true
console.log(reg.test("deep")); //=>true
console.log(reg.test("some")); //=>false

7. 其它正则捕获的方法


7.1 test也能捕获(本意是匹配)

let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"0"console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"1"console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"2"console.log(reg.test(str)); //=>false
console.log(RegExp.$1); //=>"2" 存储的是上次捕获的结果//=>RegExp.$1~RegExp.$9:获取当前本次正则匹配后,第一个到第九个分组的信息

7.2 replace 字符串中实现替换的方法(一般都是伴随正则一起使用)

场景需求:现有字符串 str = "Java@2019|Java@2020" ,把"Java"替换成"JavaScript"。

方法一:不用正则,执行一次只能替换一个。所以这里需要执行两次.replace()

let str = "Java@2019|Java@2020";
str1 = str.replace("Java","JavaScript").replace("Java","JavaScript");
console.log(str1); //=>JavaScript@2019|JavaScript@2020

方法二:使用正则,但是有问题。

// 每一次替换都是从字符串第一个位置开始找的(类似于正则捕获的懒惰性)
// 所以这里有个问题:如果把Java替换成JavaScript
let str = "Java@2019|Java@2020";
str2 = str.replace(/Java/,"JavaScript").replace(/Java/,"JavaScript");
console.log(str2); //=>"JavaScriptScript@2019|Java@2020"/* * 可以看出这里的输出结果有误。* 因为懒惰性,每一次都从字符串第一个位置开始查找* 所以 第一次replace结果为 "JavaScript@2019|Java@2020"。*     第二次replace结果为 "JavaScriptScript@2019|Java@2020"*/

方法三:基于正则g可以正常实现需求

let str = "Java@2019|Java@2020";
str3 = str.replace(/Java/g,"JavaScript");
console.log(str3); //=>JavaScript@2019|JavaScript@2020

正则表达式(三)正则的捕获相关推荐

  1. 正则表达式 - 常用的正则表达式级正则的捕获

    常用的正则表达式 验证是否为有效数字 /* * 规则分析 * 1. 可能出现 + - ,也可能不出现 * 2. 一位0-9都可以,多位首位不能为0 * 3.小数部分可能有可能没有,一旦有后面必须有小数 ...

  2. JS 正则表达式(正则匹配RegExp)

    JavaScript实现对象深拷贝的方法(5种) 知识回调(不懂就看这儿!) 场景复现 核心干货 举例引入 关于RegExp对象 语法 修饰符--区分大小写和全局匹配 方括号--查找某个范围内的字符 ...

  3. shell匹配IP和shell正则匹配捕获引用

    为什么80%的码农都做不了架构师?>>>    在服务器上加了一个服务检测机制,用到正则来匹配IP和捕获分组.shell和其他语言一样也可以使用正则分组捕获,不过不能使用 $1或\1 ...

  4. Python正则表达式(正则、regular、re)讲解,及常用正则:匹配邮箱、身份证、手机号、IP地址、URL、HTML等

    正则表达式(正则.regular.re)是 Python 中最常见的编程技巧,很多时候,一个好的正则表达式可以抵上几十行代码.比如:匹配(校验)邮箱.身份证.手机号.IP地址.URL.HTML等. 正 ...

  5. [.net 面向对象程序设计进阶] (4) 正则表达式 (三) 表达式助手

    [.net 面向对象程序设计进阶] (2) 正则表达式(三) 表达式助手 上面两节对正则表达式的使用及.NET下使用正则表达式作了详细说明,本节主要搜集整理了常用的正则表达式提供参考. 此外为了使用方 ...

  6. mysql 正则匹配 捕获组_常用正则表达式 捕获组(分组)

    1.img标签 //,空格后src以'或"开始..... Regex reg = new Regex("]*\\ssrc=(['\"]+[^<>'\" ...

  7. 正则表达式中的非捕获组是什么?

    非捕获组(即(?:) )如何在正则表达式中使用,它们有什么用? #1楼 在复杂的正则表达式中,您可能会希望使用大量的组,其中一些用于重复匹配,而另一些则提供反向引用. 默认情况下,与每个组匹配的文本会 ...

  8. 正则表达式三种匹配模式:贪婪模式,勉强模式,占有模式的区别

    正则表达式一共有三种模式:贪婪模式.勉强模式.侵占模式. 我在做项目的时候,曾领教过正则"回溯陷阱"的厉害,所以,今天做个总结下正则常见的两种模式的区别: [贪婪模式]:正则表达式 ...

  9. JAVA写HTTP代理服务器(三)-https明文捕获

    上一篇用netty实现的http代理服务器还无法对https报文进行解密,原因也说了,就是服务器的私钥不在我们这,根据RSA公钥加密私钥解密的特性,如果我们没有私钥的话是不可能获取到https的真实内 ...

最新文章

  1. 深入理解C语言的define
  2. python编程超市购物系统_python实现简单购物车系统(练习)
  3. [技术转载]C#知识点集合 (面试必备)
  4. window 10下 Spark 安装简单使用
  5. MOSN 多协议扩展开发实践
  6. 前端学习(2413):关于有默认子路由的路由name
  7. 请编写程序编写前n个整数的全排列_26道基础算法题(请查收)
  8. pitr 原理_PostgreSQL基于时间点恢复(PITR)
  9. java suppresslint_Java 注解用法详解——@SuppressWarnings
  10. 两个方法事务调用问题
  11. Linux Iptables 语法大全
  12. 代码审计工具Fortify 17.10及Mac平台license版本
  13. linux拷贝文件和目录命令,Linux 命令 - cp: 拷贝文件和目录
  14. 开头的单词_学Z字母本义和引申义,初高中Z开头的单词几分钟全部轻松记忆!...
  15. (离散数学)用谓词逻辑推理的方法证明下面推理的有效性。要求按照推理的格式书写推理过程。
  16. DSP_TMS320F28335_PIE学习笔记
  17. Adam和学习率衰减(learning rate decay)
  18. 【人工智能】人工智能学习常用社区
  19. 网狐卓越版本内核引擎、卓越内核(源码,源码,源码)
  20. jk触发器上升沿怎么看_jk触发器波形图_jk触发器波形图怎么画

热门文章

  1. 关于公众号的运营干货与常用的工具
  2. 【法规】投标申请人资格预审须知-刘俊平
  3. 数字人民币上线红包新功能;高通开始人员优化;第一批AI绘画公司开始倒闭;网易云音乐加码声音社交;统计学课程(2023版);GitHub今日热榜 | ShowMeAI资讯日报
  4. 搜狗多账户cookies最新接口可用推送工具免费使用【2020】
  5. visual studio装哪些_全球有哪些院校的平面设计好?
  6. Docker--(三)--测试
  7. 商城系统开发,使用微信服务号好?还是小程序?
  8. [CSS] 浮动 float属性、clear属性详解
  9. 三个思维结构:黄金圈法则、金字塔结构、PREP结构
  10. 936烙铁芯发热芯型号判断