正则表达式进阶玩法

正则的捕获

实现正则捕获的方法

  • 正则RegExp.prototype中的方法
    • exec
    • test
  • 字符串String.prototype上支持正则表达式的处理方法。
    • replace
    • match
    • split
/** 
 * 基于exec的正则捕获
 *  1.捕获到的结果为null,或者是一个数组。
 *      数组第一项:本次捕获到的内容。
 *      其余项:对应小分组本次单独捕获的内容。
 *      index:当前捕获内容在字符串中的索引。
 *      input;原始字符串
 *  2.每执行一次,只能捕获到一个符合正则规则的内容,但是默认情况下,无论执行多少次,永远只能匹配到第一个,其余的并捕获不到,这是正则捕获的懒惰性。默认只捕获第一个。
 * 
 *      reg.lastIndex   当前正则的下一次匹配的起始索引位置。
 *      懒惰性的原因: lastIndex默认值为0,默认情况下不会被修改。
 *      解决方法,调用全局修饰符g
 * /

未加 \g 全局匹配

let str = "cr2019cr2020cr2021";
//此种匹配,正则只会匹配默认的第一个。
let reg = /\d+/;
console.log(reg.exec(str));
console.log(reg.lastIndex);
console.log(reg.exec(str));
console.log(reg.lastIndex);
console.log(reg.exec(str));
console.log(reg.lastIndex);
console.log(reg.exec(str));
console.log(reg.lastIndex);

加 \g 全局匹配

let str2 = "cr2019cr2020cr2021";
let reg2 = /\d+/g;
console.log(reg2.exec(str2));
console.log(reg2.lastIndex);
console.log(reg2.exec(str2));
console.log(reg2.lastIndex);
console.log(reg2.exec(str2));
console.log(reg2.lastIndex);
console.log(reg2.exec(str2));
console.log(reg2.lastIndex);

匹配多个

~ function(){
    function execAll(str = ""){
        //=>    str:要匹配的字符串。
        //=>    this:RegExp的实例(当前操作的正则)
        //=>    字符串进来后的第一件事就是判断有没有设置全局G
        if(!(this.global)){
            return this.exec(str);
        }

        //=>    ARRAY:存储最后捕获的所有信息     RES存储每一次捕获内容(数组)
        let array = [],
            res = this.exec(str);
        while(res){
            //=> 把每一次捕获的内容RES[0]存放到数组中。
            array.push(res[0]);
            //=> 只要捕获的内容不为NULL,则继续捕获下去。
            res = this.exec(str);
        }
        return array.length === 0? null:array;
    }
    RegExp.prototype.execAll = execAll;
}();

let str = "cr2019cr2020cr2021";
let reg = /\d+/g;
//正则表达式的做法
//说白了,就是我自己又把字符串里的match方法写了一遍而已。
console.log(reg.execAll(str));

//但是运用字符串MATCH方法,就可以直接进行匹配。
console.log(str.match(reg));

正则的分组捕获

不设置g只匹配一次,exec和match获取的结果一致(既有大正则的匹配,又有小正则的匹配的信息)

let str = "{2020}年{7}月{13}日";
let reg = /\{(\d+)\}/;
console.log(reg.exec(str));
console.log(str.match(reg));

在这里插入图片描述



多次匹配情况下,match只能把大正则匹配的内容捕获到,不能捕获小分组的内容。

let str = "{2020}年{7}月{13}日";
let reg = /\{(\d+)\}/g;
console.log(str.match(reg));
//______________________________________
//既然无法全部匹配到,那么只好自己写循环获取啦!!!!!

let arrayBig = [],
	arraySmall = [],
	res = reg.exec(str);
while(res){
	let [big,small] = res;
	arrayBig.push(big);
	arraySmall.push(small);
	res = reg.exec(str);
}
console.log(arrayBig,arraySmall);

在这里插入图片描述


分组的引用

  • 有“book”,“look”,“good”等等类似的单词
  • 通过调用 \数字的形式让其代表和对应的分组出现一模一样的内容。
let str = "book";
let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/;
console.log(reg.test(str));

正则捕获的贪婪性

  • 正则捕获的贪婪性,默认情况下,正则捕获的时候,是按照正则当前所匹配的最长结果来获取的。
  • 在量词元字符后面设置问号(?),则取消了贪婪性。(按照正则匹配的最短结果来获取。)
let str = "cr2020@cr2021";
let reg = /\d+/g;
console.log(str.match(reg));    //[ '2020', '2021' ]

let reg2  = /\d+?/g;
console.log(str.match(reg2));

在这里插入图片描述

  • 问号左边是非量词元字符的时候:本身代表量词元字符,出现零到一次。
  • 问号左边是量词元字符的时候:表示取消捕获时的贪婪性。

其它正则捕获的方法

  1. test 也能捕获(本意是匹配)
let str = "{2020}年{7}月{13}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str));
console.log(RegExp.$1);

console.log(RegExp.$1) ~ console.log(RegExp.$9) : 获取当前本次正则匹配后,第一个到第九个分组的信息。

在这里插入图片描述
2. replace 字符串中实现替换的方法(一般都是伴随正则一起使用)

let str = "cr@2020|cr2021";
//=>把 "cr" 替换成 “端科技”
//1. 不用正则表达式,执行一次只能替换一个。
// str = str.replace("cr","端科技").replace("cr","端科技");
// console.log(str);

//2。用正则表达式直接进行替换
str = str.replace(/cr/g,"端科技");
console.log(str);

上练习题

把时间字符串进行处理。将 2020-7-13 变成 2020年7月13日

let time = "2020-7-13";
let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
time = time.replace(reg,"$1年$2月$3日");
console.log(time);


//=>还可以这样处理[str].replace([reg],[function])
//首先拿到REG和TIME进行匹配捕获,能匹配几次就会把传递的函数执行几次(而且是匹配一次,就执行一次。)
//不仅把方法执行,而且REPLACE还给方法传递了实参信息(和exec捕获的内容一致的信息。:大正则匹配的内容和小分组的内容)
//在函数中,我们返回的是啥,就把当前大正则匹配的内容替换成啥。
time = time.replace(reg,(big,$1,$2,$3)=>{
    //=>这里的$1~$3是我们自己设置的变量
    console.log(big,$1,$2,$3);
});

time = time.replace(reg,(...arg)=>{
    let [,$1,$2,$3] = arg;
    $2.length<2?$2="0"+$2:null;
    $3.length<2?$3="0"+$3:null;
    return $1+"年"+$2+"月"+$3+"日";
});
console.log(time);  

单词首字母大写

let str = "good good study, day day up!";
let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g;
//=>函数被执行了六次,每一次都把正则信息传递给函数
//=>每一次ARG:["good","g"] ["good","g"] ["study","s"]...

str = str.replace(reg,(...arg)=>{
    let [content,$1] = arg; 
    $1 = $1.toUpperCase();
    content = content.substring(1);
    return $1+content;
});
console.log(str);

验证一个字符串中哪个字母出现次数最多,出现了多少次?

做法一

let str = "ni shi bu shi zui bang de yi ge xiao hai a      ?";
str = str.replace(/\s*/g,"");
let obj = {};
[].forEach.call(str,char=>{
    if(typeof obj[char] !== "undefined"){
        obj[char]++;
        return;
    }
    obj[char] = 1;
});

let max = 1,
    res = [];
for(let key in obj){
    let item = obj[key];
    item > max ? max = item : null;
}
for(let key in obj){
    let item = obj[key];
    if(item === max){
        res.push(key);
    }
}

console.log(`出现次数最多的字符是:${res},出现了${max}次。`);

做法二

let str = "ni shi bu shi zui bang de yi ge xiao hai a      ?";

str = str.split("").sort((a,b) => a.localeCompare(b)).join("");
let reg = /([a-zA-Z])\1+/g;
let ary = str.match(reg).sort((a,b) => b.length - a.length);
console.log(`出现次数最多的字符是:${ary[0].slice(0,1)},出现了${ary[0].length}次。`);

做法三

let str = "i i i j j j sddsfecwecsdvap,?";
str = str.split("").sort((a,b) => a.localeCompare(b)).join("");
let reg = /([a-zA-Z])\1+/g;
let ary = str.match(reg).sort((a,b) => b.length - a.length);
let max = ary[0].length,
    res = [ary[0].substr(0,1)];
for(let i = 1;i<ary.length; i++){
    let item = ary[i];
    if(item.length < max){
        break;
    }
    res.push(item.substr(0,1));
}

console.log(`出现次数最多的字符是:${res},出现了${max}次。`);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值