正则捕获-正则捕获的懒惰型

正则的捕获

实现正则捕获的办法

  • 正则RegExp.prototype上的方法
    exec
    test
  • 字符串String.prototype上支持正则表达式处理的方法
    replace
    match
    splite

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

reg.lastIndex:当前正则下一次匹配的起始索引位置
懒惰性捕获的原因:默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远只是第一个
解决办法:全局修饰符g

let str = "zhufeng2019yangfan2020qihang2021";
let reg = /\d+/;
console.log(reg.lastIndex); //=>0 下面匹配捕获是从str索引零的位置开始找
console.log(reg.exec(str));
console.log(reg.lastIndex); //=>0 第一次匹配捕获完成,lastIndex没有改变,所以下一次exec依然是从字符串最开始找,找到的永远是第一个匹配到的


let reg = /\d+/g;
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"...]


let reg = /\d+/g;
if (reg.test(str)) { //=>验证一下:只有正则和字符串匹配我们在捕获	
	console.log(reg.lastIndex); //=>11 基于TEST匹配验证后,LASTINDEX已经被修改为第一次匹配后的结果,所以下一次捕获不再从头开始了
	console.log(reg.exec(str)); //=>["2020"...]
}

需求:编写一个方法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 str = "zhufeng2019yangfan2020qihang2021";
let reg=/\d+/g;
reg.execAll(str) //[2019,2020,2021]

//=>字符串中的MATCH方法,可以在执行一次的情况下,捕获到所有匹配的数据(前提:正则也得设置G才可以)
let reg = /\d+/g;
console.log(reg.execAll("珠峰2019@2020培训"));
console.log("珠峰2019@2020培训".match(reg));//以上方法是match的源码

正则的分组捕获

//=>第一项:大正则匹配的结果
//=>其余项:每一个小分组单独匹配捕获的结果
//=>如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于?:来处理

let str = "130828199012040112";
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));
//=>["130828199012040112", "130828", "1990", "12", "04", "1", index: 0, input: "130828199012040112"]

需求:既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到 {0} 还需要单独获取0
let str = “{0}年{1}月{2}日”;

//=>不设置g只匹配一次,exec和match获取的结果一致(既有大正则匹配的信息,也有小分组匹配的信息)
let reg = /\{(\d+)\}/;
console.log(reg.exec(str));
console.log(str.match(reg));
//["{0}", "0",...]
let reg = /\{(\d+)\}/g;
//console.log(str.match(reg)); //=>["{0}", "{1}", "{2}"] 多次匹配的情况下,match只能把大正则匹配的内容获取到,小分组匹配的信息无法获取
	let aryBig=[],
	    arySmall=[],
	    res=reg.exec(str);
	while(res){
	    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 str = "book"; //=>"good"、"look"、"moon"、"foot"...
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值