let str = "hshshs2019sdfaa2020asdw2021";
实现正则捕获的办法
- 正则RegExp.prototype上的方法
exec
test
- 字符串String.prototype上支持正则表达式处理的方法
replace
match
splite
…
基于exec实现正则的捕获
捕获到的结果是null
或者一个数组
第一项
:本次捕获到的内容
其余项
:对应小分组本次单独捕获的内容
index
:当前捕获内容在字符串中的起始索引
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
/*
- reg.lastIndex:当前正则下一次匹配的起始索引位置
- 懒惰性捕获的原因:默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远只是第一个
- 解决办法:全局修饰符g
*/
let reg = /\d+/;
console.log(reg.lastIndex); //=>0 下面匹配捕获是从STR索引零的位置开始找
console.log(reg.exec(str)); //["2019", index: 6, input: "hshshs2019sdfaa2020asdw2021", groups: undefined]
console.log(reg.lastIndex); //=>0 第一次匹配捕获完成,lastIndex没有改变,所以下一次exec依然是从字符串最开始找,找到的永远是第一个匹配到的
[全局捕获会动态修改匹配位置]
let reg = /\d+/g;
console.log(reg.exec(str)); //=>["2019"...]
console.log(reg.lastIndex); //=>10 设置全局匹配修饰符g后,第一次匹配完,lastIndex会自己修改
console.log(reg.exec(str)); //=>["2020"...]
console.log(reg.lastIndex); //=>19
console.log(reg.exec(str)); //=>["2021"...]
console.log(reg.lastIndex); //=>27
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); //=>10 基于TEST匹配验证后,LASTINDEX已经被修改为第一次匹配后的结果,所以下一次捕获不再从头开始了
console.log(reg.exec(str)); //=>["2020"...]
}
demo编写把所有匹配的结果捕获到
方法一
// =>需求:编写一个方法execAll,执行一次可以把所有匹配数的结果捕获到(前提正则一定要设置全局修饰符g)
~ function () {
function execAll(str = "") {
//=>str:要匹配的字符串
//=>this:RegExp的实例(当前操作的正则)
//=>进来后的第一件事,是验证当前正则是否设置了G,不设置则不能在进行循环捕获了,否则会导致死循环
//global属性是指明是搜索整个字符串还是匹配第一个。整个是true,一个是false
//let reg2 = /\d+/g; //全局
//dir(reg2 )
//global =>true
//let reg2 = /\d+/; //一个
//dir(reg2 )
//global =>false
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("a'sa2019@2020asaffd")); // =>["2019", "2020"]
方法二match(不适用于分组捕获)
//=>字符串中的MATCH方法,可以在执行一次的情况下,捕获到所有匹配的数据(前提:正则也得设置G才可以)
console.log("ssr'r2019@2020sss".match(reg)); //=>["2019", "2020"]
分组捕获
正则的分组捕获
//=>第一项
:大正则匹配的结果
//=>其余项
:每一个小分组单独匹配捕获的结果
//=>如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于?:
来处理
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}年{1}月{2}日,既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到 {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]$/; //=>分组引用就是通过“\数字”让其代表和对应分组出现一模一样的内容,oo,ee,让其代表和()里同样的内容
console.log(reg.test("book")); //=>true
console.log(reg.test("deep")); //=>true
console.log(reg.test("some")); //=>false
正则捕获的贪婪性
let str = "ad2019@2020we";
//=>正则捕获的贪婪性:默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
let reg = /\d+/g;
console.log(str.match(reg)); //=>["2019","2020"]
//=>在量词元字符后面设置?:取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)
reg = /\d+?/g;
console.log(str.match(reg)); //=>["2", "0", "1", "9", "2", "0", "2", "0"]
问号在正则中的五大作用:
- 问号左边是非量词元字符:本身代表量词元字符,出现零到一次
- 问号左边是量词元字符:取消捕获时候的贪婪性
- (?:) 只匹配不捕获
- (?=) 正向预查
- (?!) 负向预查
其它正则捕获的方法
-
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:获取当前本次正则匹配后,第一个到第九个分组的信息
-
replace 字符串中实现替换的方法(一般都是伴随正则一起使用的)
let str = "sr@2019|sr@2020"; //=>把"sr"替换成"shao" //1.不用正则,执行一次只能替换一个 /* str = str.replace("sr","shao").replace("sr","shao"); console.log(str); */ //2.使用正则会简单一点 str = str.replace(/sr/g,"shao"); console.log(str);
let str = "sr@2019|sr@2020"; //=>把"sr"替换为"sr111" //str=str.replace("sr","sr111").replace("sr","sr111"); //"sr111@2019|sr@2020" 每一次替换都是从字符串第一个位置开始找的(类似于正则捕获的懒惰性) //=>基于正则g可以实现 str = str.replace(/sr/g,"sr111");
案例:把时间字符串进行处理
let time = "2019-08-13"; //=>变为"2019年08月13日" let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/; //=>这样可以实现 //time = time.replace(reg,"$1年$2月$3日"); //console.log(time); //=>2019年08月13日 //=>还可以这样处理 [str].replace([reg],[function]) //1.首先拿REG和TIME进行匹配捕获,能匹配到几次就会把传递的函数执行几次(而且是匹配一次就执行一次) //2.不仅把方法执行,而且REPLACE还给方法传递了实参信息(和exec捕获的内容一致的信息:大正则匹配的内容,小分组匹配的信息....) //3.在函数中我们返回的是啥,就把当前大正则匹配的内容替换成啥 /* 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+"日"; });
单词首字母大写
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); //=>"Good Good Study,Day Day Up!"
验证一个字符串中那个字母出现的次数最多,多少次?
/*==(去重思维)==*/ let str = "dfsfdgfhrtvjoemk"; 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 = "qwefgskoilxsg"; str = str.split('').sort((a, b) => a.localeCompare(b)).join(''); // console.log(str);//=>"aeefghhhiilnnoopsuuuxzz" let ary = str.match(/([a-zA-Z])\1+/g).sort((a, b) => b.length - a.length); // console.log(ary); //=>["hhh", "uuu", "ee", "ii", "nn", "oo", "zz"] 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}次`); /*==:从最大到最小去试找==*/ let str = "qwefgskoilxsg", max = 0, res = [], flag = false; str = str.split('').sort((a, b) => a.localeCompare(b)).join(''); for (let i = str.length; i > 0; i--) { let reg = new RegExp("([a-zA-Z])\\1{" + (i - 1) + "}", "g"); str.replace(reg, (content, $1) => { res.push($1); max = i; flag = true; }); if (flag) break; } console.log(`出现次数最多的字符:${res},出现了${max}次`);
其它方法:formatTime 、 queryURLParams 、 millimeter
~ function () { /* * formatTime:时间字符串的格式化处理 * @params * templete:[string] 我们最后期望获取日期格式的模板 * 模板规则:{0}->年 {1~5}->月日时分秒 * @return * [string]格式化后的时间字符串 * by sr on 2019/08/13 */ function formatTime(templete = "{0}年{1}月{2}日 {3}时{4}分{5}秒") { let timeAry = this.match(/\d+/g); return templete.replace(/\{(\d+)\}/g, (...[, $1]) => { let time = timeAry[$1] || "00"; return time.length < 2 ? "0" + time : time; }); } /* * queryURLParams:获取URL地址问号和面的参数信息(可能也包含HASH值) * @params * @return * [object]把所有问号参数信息以键值对的方式存储起来并且返回 * by sr on 2019/08/13 */ function queryURLParams() { let obj = {}; this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, $1, $2]) => obj[$1] = $2); this.replace(/#([^?=&#]+)/g, (...[, $1]) => obj['HASH'] = $1); return obj; } /* * millimeter:实现大数字的千分符处理 * @params * @return * [string]千分符后的字符串 * by sr on 2019/08/13 */ function millimeter() { return this.replace(/\d{1,3}(?=(\d{3})+$)/g, content => content + ','); } /* 扩展到内置类String.prototype上 */ ["formatTime", "queryURLParams", "millimeter"].forEach(item => { String.prototype[item] = eval(item); }); }();
网友评论