正则的捕获
实现正则捕获的方法
- 正则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));
- 问号左边是非量词元字符的时候:本身代表量词元字符,出现零到一次。
- 问号左边是量词元字符的时候:表示取消捕获时的贪婪性。
其它正则捕获的方法
- 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}次。`);