正则讲了很久,也拖了很久,今天看看怎么用吧,后续更文应该会比较准勤快了。:-)
书接上文【正则笔记(2)】。这次我们来看看正则的使用:
(注:斜体表示为对应规则写出的正则表达式)
一、 常用的正则表达式:
1. 验证是否为有效数字:
规则分析:
a. 可能出现 + - 号,也可能不出现。那么根据该规则我们可以写出正则:[+-]?
b.如果是1位数字那么0-9都可以,如果是多位数字,则首位不能为0。则我们可以写出正则:\d|([1-9]\d+)
c.小数部分可能有也可能没有。一旦有小数部分则必须有小数点+数字 。对应正则:(\.\d+)?
综合以上的几个部分,所以我们知道验证有效数字的正则可以写成:
let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
通过上面的分析,发现了吗?写正则表达式一般我们是按位来写。
2.验证密码的正则:
规则分析:
a. 数字,字母,下划线
b. 6-16位
为了让各位看客体验一下正则的强大,我们先用传统JS的方法来校验一下密码:
//不用正则:let val = userPassInp.value; //这里表示从密码框中获取密码值function checkPass(val) { if (val.length<6 || val.length>16) { alert('长度必须介于6-16位之间'); return; } let area = ['a','/**...这里表示的是a-z,A-Z,0-9,_*/']; // 这里应该是包含字母数字下划线的数组 for(let i=0; i<val.length; i++) { let char = val[i]; if (!area.includes(char)) { alert('密码格式不正确'); return; } }}
是不是有点冗长?那么来看一下正则校验密码:
let reg2 = /^\w{6-16}$/;let flag = reg2.test(val); // 若 flag 为true则表示正确
简单多了吧,有没有分分钟爱上正则?
3.验证真实姓名:
规则:
a.汉字。那么应该对应中文第一个汉字到最后一个汉字的Unicode编码值,即:/^[\u4E00-\u9FA5]$/
b. 名字长度2-10位。即:{2,10}
c.可能有译名的情况发生,比如:'尼古拉·赵四',·后面暂定1-10位吧,可以酌情修改。(·[\u4E00-\u9FA5]{1,10})?
let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{1,10})?$/;reg.test('孙尚香'); // truereg.test('cos'); // false 必须是中文reg.test('尼古拉·赵四'); // true
4.验证邮箱:
规则:
a.开头必须是字母、数字、下划线 (可以1-多次)。即: \w+
比如:
sun-shang-xiang sun.shang.xiang
sun-shang.xiang
b.还可以是 -字母数字下划线 或者 .数字字母下划线, 整体0到多位。即: ((-\w+)|(\.\w+))*(注:邮箱的名字由数字、字母、下划线、中划线、点、几部分组成,但是 中划线和点不能连续出现,也不能作为开始)
c. @符后面紧跟着:数字,字母(可以是一直多位)。即: [A-Za-z0-9]+
d. 我们还需要对@符号后面的内容做一些补充,因为:
①有可能是多域名邮箱比如:.com.cn
②也可能企业域名 ssx@shuhan-wangchao-office.com //孙尚香@蜀汉-王朝-办公室.com
所以:((\.|-)[A-Za-z0-9]+)*
e- 匹配最后的域名,比如:(.com .cn .org .net .edu)。即:\.[A-Za-z0-9]+
综上,邮箱的正则为:
let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
5.身份证号码:
规则:
a.一共18位
b. 最后以为可能是X
c. 身份证前六位是省市县
d. 中间8位是出生年月日
e. 最后四位:
最后1位是X或者数字
倒数第二位偶尔是女 奇数是男
其余的是经过算法算出来
let reg = /^\d{17}(\d|X)$/;
我们来分析一下上面这一段正则:
在这里我们遇到了 () 的第二个作用:分组捕获。
不仅可以把大正则匹配的信息捕获到,还可以单独捕获到每个小分组的内容
比如:
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/;reg.exec('410521199303088019'); // 正则捕获 捕获的结果是个数组 包含了每个小分组单独获取的内容
我们来看一下分组捕获到的具体内容:
0: "410521199303088019"
1: "410521"
2: "1993"
3: "03"
4: "08"
5: "1"
6: "9"
groups: undefined
index: 0
input: "410521199303088019"
length: 7
二、两种创建正则的方式之间的区别:
1- 字面量创建:
let reg = /\\/;reg.test('\\'); //true//或者这样:let reg2 = /\d+/g;
2- 构造函数模式创建: 这种写法RegExp有2个参数:元字符字符串 和 修饰符字符串
let reg = new RegExp('\\d+','g');// ==>构造函数因为传递的是字符串,\需要些两个才代表斜杠。
说明:
1.正则表达式中的部分内容是变量存储的值
2.两个斜杠包起来的部分都是元字符 (如果正则中要包含某个变量的值,则不能使用字面量方式创建)
3.如果正则中包含某个变量只能使用构造函数的形式 (因为它传递的是字符串,只有这样才能进行字符串拼接)
举个栗子叭。
字面量形式:
let type = 'cos';let reg = /^@"+type+"@$/;reg.test("@cos@"); //==> falsereg.test('@"""typeeeee"@'); //==> true 因为正则中的 + 号被作为元字符了
构造函数形式:
let reg = new RegExp('^@'+ type +'@$');reg5.test("@cos@"); // true
三、正则捕获:
1- 实现正则捕获的方法:
正则RegExp.prototype上的方法
exec
test
2- 字符串String.prototype上支持正则表达式处理的方法:
replace
match
splite
...
常用正则表达式的方法:
exec:一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回 null)。test:一个在字符串中测试是否匹配的RegExp方法,它返回 true 或 false。match:一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null。matchAll:一个在字符串中执行查找所有匹配的String方法,它返回一个迭代器(iterator)。search:一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。replace:一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。split:一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法。
3-正则捕获的懒惰性:
如果我们想捕获字符串str中所有的数字:
let str = "cos2019yangfan2020qihang2021";// 捕获str中所有的数字 (首先正则得匹配才行)// 实现正则捕获的前提是 当前正则要和对应字符串匹配,如果不匹配捕获的结果为nulllet reg = /^\d+/;reg.test(str); //==> falsereg.exec(str); //==> null 没有匹配到所以返回nulllet reg2 = /\d+/;reg2.test(str); //==> falsereg2.exec(str); //==> 得到的结果是个数组 ["2019", index: 3, input: "cos2019yangfan2020qihang2021", groups: undefined]
基于exec实现正则的捕获:
1-捕获到的结果是null或者一个数组 。
数组第一项:为本次捕获到的内容
其余项是对应小分组单独捕获的内容
index: 当前捕获的结果在字符串中的起始位置
input: 原始字符串
2-每执行一次exec方法只能捕获到一个符合正则规则的,但是默认情况下,我们执行多次,获取的结果永远都是第一个匹配到的,其余的捕获不到,这个叫做正则捕获的懒惰性。
正则捕获懒惰性的原理:
这一切都要从RegExpObject.lastIndex 说起,lastIndex 属性用于规定下次匹配的起始位置。
正则捕获懒惰性的原因是:默认情况下 lastIndex 的值不会被修改,
每一次都是从字符串开始位置查找,
所以找到的永远是第一个
解决办法:使用全局修饰符 g
// exec原理:letstr = "cos2019yangfan2020qihang2021";letreg = /\d+/;reg.lastIndex; //==> 0 下面匹配捕获是从str索引为0的位置开始找reg.exec(str); //==> ['2019',...]reg.lastIndex; //==> 0 注意:lastIndex没有改变
第一次匹配捕获完成,lastIndex没有改变,所以下一次exec依然是从字符串最开始找,找到的永远是第一个匹配到的,所有的捕获方法都遵循这个规则(因为是正则本身的机制)。
正则捕获懒惰型的解决方案:修饰符 g
let str = "cos2019yangfan2020qihang2021";let reg = /\d+/g;reg.lastIndex; //==> 0reg.exec(str); //==> ['2019'...]reg.lastIndex; //==> 7// 注意:设置全局匹配修饰符g后,第一次匹配完,lastIndex的值会自己修改reg.exec(str); //==> ['2020'...]reg.lastIndex; //==> 18reg.exec(str); //==> ['2021'...]reg.lastIndex; //==> 28reg.exec(str); //==> null 当全部捕获后,再次捕获的结果是null,但是lastIndex又回到了初始值0,再次捕获,又从第一个开始了...reg.lastIndex; //==> 0reg.exec(str); //==> ['2019'...]
仔细看会发现,当exec匹配到null之后,又从字符串开端重新开始匹配了。这是因为,当全部捕获后,再次捕获的结果是null,但是lastIndex又回到了初始值0,再次捕获,又从第一个开始了...
重要事项:不具有标志 g 和不表示全局模式的 RegExp 对象不能使用 lastIndex 属性。
因为我们说只有正则能够在字符串中匹配到值的情况下,捕获才有意义,所以可能可能有人会这么想:是不是可以先使用test()方法来检测一下正则能否匹配到字符串中的值,如果能匹配到值,再进行捕获。
但是这种方案是不对的:
// 如果字符串不符合正则,那么就无法捕获// 下面的解决方案是有问题的:let str = "cos2019yangfan2020qihang2021";let reg = /\d+/g;if (reg.test(str)) { // 验证一下: 只有正则和字符串匹配我们再捕获 console.log(reg.lastIndex); // 7 基于test匹配验证后, console.log(reg.exec(str)); // ==> ['2020',...] lastIndex已经被修改为第一次匹配后的结果,所以下一次捕获不再从头开始了}
存在的问题: 如果这么写那么我们就没有办法匹配到第一个符合规则的值了。
于是,我们提出一个需求:编写一个方法execAll,执行一次可以把所有匹配的结果捕获到(前提,正则一定要设置全局修饰符g)
~function() { function execAll(str = '') { // 进来后的第一件事,就是验证当前正则是否设置了g, // 不设置则不能再进行循环捕获了,否则会导致死循环 if(!this.global) return this.exec(str); // => str:要匹配的字符串 // => this:RegExp的示例(当前操作的正则) // ary存储最后所有捕获的信息 reg存储每一次捕获的内容 let ary = []; let res = this.exec(str); while(res) { ary.push(res[0]); // 把每一次捕获的内容存放到数组当中 // => 只要捕获的内容不为null,则继续捕获下去 res = this.exec(str); } return ary.length === 0 ? null : ary; } RegExp.prototype.execAll = execAll;}();
使用:
// 加g:let str = "cos2019yangfan2020qihang2021";let reg = /\d+/g;reg.execAll(str); // ['2019,'2020','2021']let str2 = 'hhh';let str3 = '12@13hhh'reg.execAll(str2); // nullreg.execAll(str3); // ['12,'13']
// 不加g的情况下:let reg2 = /\d+/;reg2.execAll(str2); // nullreg2.execAll(str3); // ["12", index: 0, input: "12@13hhh", groups: undefined]
其实还有一种办法,就是直接使用字符串的match方法:
str3.match(reg2); // ["12", "13"]// 字符串中的match方法,可以在执行一次的情况下,捕获到所有匹配的数据(前提是正则必须加g才可以)
4-正则的分组捕获:
身份证号码:
let str = '610521199003020017';let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;reg.test(str); // truereg.exec(str); // ["610521199003020017", "610521", "1990", "03", "02", "1", "7", index: 0, input: "610521199003020017", groups: undefined]str.match(reg);// ["610521199003020017", "610521", "1990", "03", "02", "1", "7", index: 0, input: "610521199003020017", groups: undefined]
我们对上述正则不活的内容做一个分析:
a.数组第一项是大正则匹配的结果
b.其余项:每一个小分组单独匹配捕获的结果
c.如果设置了分组(改变优先级)但是捕获的时候不需要单独捕获,可以基于?:(只匹配不捕获)来处理
d.比如我不想要最后一项(因为没有用),我们不能去掉小括号,因为|会存在优先级的问题,所以我在最后一项的括号中添加一个 ?: 表示只匹配不捕获(?:\d|X) 这个时候就不会捕获到最后的一项了
5-分组捕获
比如我们定义了一个字符串时间格式为:{2019}年{11}月{8}日
既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到{0},还需要单独获取0
let str = "{2019}年{11}月{8}日";let reg = /\{\d+\}/; reg.exec(str); //["{2019}", index: 0, input: "{2019}年{11}月{8}日", groups: undefined]str.match(reg); //["{2019}", index: 0, input: "{2019}年{11}月{8}日", groups: undefined]
这种情况下只能捕获到大正则不能捕获小分组。
那如何才能获取到小分组呢:
// 加小括号,分组捕获:let str = "{2019}年{11}月{8}日";let reg = /\{(\d+)\}/;reg.exec(str); // ["{2019}", "2019", index: 0, input: "{2019}年{11}月{8}日", groups: undefined]str.match(reg); // ["{2019}", "2019", index: 0, input: "{2019}年{11}月{8}日", groups: undefined]
分组捕获,先匹配大正则,再把对应的小分组匹配到。
但问题又来了,如果我想多次匹配呢?
// 加小括号,加g:let str = "{2019}年{11}月{8}日";let reg = /\{(\d+)\}/g;reg.exec(str); // ["{2019}", "2019", index: 0, input: "{2019}年{11}月{8}日", groups: undefined]str.match(reg); // ["{2019}", "{11}", "{8}
稍微用心的同学肯定又发现了,多次匹配的情况下,match只能把大正则匹配的内容获取到,小分组匹配的信息无法获取。
卧槽?这……呵呵哒,怎么办?针对这种match无法匹配小括号中的正则的情况,我自己写了一个函数:
let str = "{2019}年{11}月{8}日";let reg = /\{(\d+)\}/g;let arrBig = [], // 大正则匹配的内容 arrSmall = [], // 小分组匹配的内容 res = reg.exec(str); while(res) { let [big,small] = res; arrBig.push(big); arrSmall.push(small); res = reg.exec(str);}console.log(arrBig, arrSmall); // ["{2019}", "{11}", "{8}"] ["2019", "11", "8"]
6-正则分组引用,
一般如果看到两个一样,比如:book ,oo 一样,那么就要考虑正则的分组引用,这里也就看到了分组的第三个作用:分组引用
let str = 'book'; // 类似 good look moon foot 这种...let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/; // 分组引用就是通过 "\数字" 让其代表和对应分组出现一模一样的内容reg.test(str); // =>truereg.test('str'); // =>falsereg.test('week'); // =>truereg.test('weeks'); // =>false
7-正则捕获的贪婪性:
let str = 'cos2019扬帆2020起航2021';let reg = /\d+/g;str.match(reg); // ["2019", "2020", "2021"]// 我们发现:把所有跟正则匹配的东西都拿到了
我们发现上面的代码 str.match(reg) 把所有跟正则匹配的东西都拿到了,也就是把像2019这样的数字整个都拿到了,而不是分开一个一个拿到了 '2', '0', '1', '9' 这样的单个数字。这是因为正则捕获的贪婪性。
正则捕获的贪婪性:默认情况下正则捕获的时候是按照当前正则所匹配的最长结果来获取的
这个是正则捕获的贪婪性。
那么如果我们不希望这样我们应该怎么做?
可以在量词元字符后面设置? 取消捕获时候的贪婪性 (按照正则匹配的最短结果来获取)
reg = /\d+?/g;str.match(reg); //["2", "0", "1", "9", "2", "0", "2", "0", "2", "0", "2", "1"]
*问号在正则中的5大作用:
1- 问号左边是非量词元字符:本身代表量词元字符,出现0-1次
2- 问号左边出是量词元字符:取消捕获时候的贪婪性
3- (?:) 只匹配不捕获
4- (?=) 正向预查
5- (?!) 负向预查
*小括号用于分组,分组的3个作用:
1- 改变有优先级
2- 分组捕获
3- 分组引用
四、其他正则捕获的方法
1- test也能捕获(本意是匹配)
RegExp.$1~RegExp.$9,获取当前正则匹配后,第一个到第九个分组的信息
let str = "{2020}年{2}月{28}日";let reg = /\{(\d+)\}/g;reg.test(str); // => trueRegExp.$1 // => 2020reg.test(str); // => trueRegExp.$1 // => 2reg.test(str); // => trueRegExp.$1 // => 28reg.test(str); // => falseRegExp.$1 // => 28 // 这里的28存储的是上次捕获的结果
2- replace 字符串中实现替换的方法(一般都是伴随正则一起使用的)
let str = 'cos@2019|cos@2020'; //需求:把'cos' 替换成 'rose'// 1- 不用正则,执行一次只能替换一个str = str.replace('cos','rose'); console.log(str);//rose@2019|cos@2020 //2- 使用正则相对简单:str = str.replace(/cos/g,'rose'); console.log(str); //rose@2019|rose@2020
3- 但是有些情况不使用正则是搞不定的,正则的优势凸显了吧,
// 比如把 cos ==> cosplaylet str = 'cos@2019|cos@2020'; str = str.replace('cos','cosplay'); //cosplay@2019|cos@2020str = str.replace('cos','cosplay'); //cosplayplayplayplay@2019|cos@2020console.log(str);// 每次都0的位置开始,所以永远替换掉的是最开始的,类似于正则捕获的懒惰型
let str = 'cos@2019|cos@2020'; str = str.replace(/cos/g,'cosplay'); // replace不会改变原有字符串console.log(str); // cosplay@2019|cosplay@2020
你看,基于正则可以一次实现。
五、实例
看了这么多东西,是不是有点烦躁了。来吧,看几个实例。
案例一:把时间字符串进行处理
let time = '2019-11-12';// ==> 变为 2019年11月12日let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;// 这种方法是可以实现的:time = time.replace(reg,'$1年$2月$3日');console.log(time); //2019年11月12日
还可以这样处理:
语法, [str].replace([reg],[function])
a-首先拿 reg 和 time 进行正则匹配捕获,能匹配几次就会把传递的函数执行几次(而且是匹配一次就执行一次)
b-不仅方法执行,而且 replace 还给方法传递了实参信息(其实就是和exec捕获的内容一致的信息:大正则匹配的内容 和 小分组匹配的信息…)
c- 在函数中,我们返回的是什么,就会把当前大正则匹配的内容替换成什么
...time = time.replace(reg,() => { // ...});
案例二:对时间字符串进行处理:
let time = "2019-1-15";// => 变为2019年1月15日let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
1- 这样写是没有问题的
time = time.replace(reg,'$1年$2月$3日'); //字符串通过replace如果第一项放入的是正则,那么后面通过$1..可以获取到分组中的信息console.log(time); //2019年11月15日
2- 还可以这样写 [str].replace([reg],[function])
a-首先拿reg 和 time进行匹配捕获,能匹配几次就会把传递的函数执行几次(而且是匹配一次,就执行一次)
b-不仅把方法执行了,而且replace还给方法传递实参信息(和exec捕获的内容一致的信息:大正则匹配的内容,小分组匹配的信息,...)
c- 函数中return的是什么,就是把当前大正则匹配结果替换成什么样
time = "2019-1-15";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); // 2019年01月15日
案例三:单词首字母大写
let str = 'good good study, day day up!';let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g;// 函数被执行了6次,每次都把正则匹配的信息传递给函数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 = 'webwangchengbin';
A- 去重思维:
let obj = {};[].forEach.call(str, char => { if (typeof obj[char] !== 'undefined') { obj[char] ++; return; } obj[char] = 1;});console.log(obj); // 通过设置一个最大值的方式let max = 1, res = [];for (let key in obj) { let item = obj[key]; item > max ? max = item : null;}console.log('max==>', max); // 3for (let key in obj) { let item = obj[key]; if (item == max) { res.push(key); }}console.log(`出现次数最多的字母是:${res},出现了${max}次`); //出现次数最多的字母是:n,出现了3次
B-排序:
letstr = 'webwangchengbin';str = str.split('').sort((a,b) => a.localeCompare(b)).join('');console.log(str); //abbceegghinnnwwlet reg= /([a-zA-Z])\1+/g;// a--如果只要第一个出现次数最多的字母,不考虑多个字母出现次数相同的情况。:let ary = str.match(reg);console.log(ary); //["bb", "ee", "gg", "nnn", "ww"]ary.sort( (a,b) => b.length - a.length);console.log(ary); // ["nnn", "bb", "ee", "gg", "ww"]console.log(`出现次数最多的字母是:${ary[0].substring(0,1)},出现了${ary[0].length}次`);// b-多个字母出现次数相同:let max = ary[0].length, res = [ary[0].substring(0,1)];for (let i=1; i let item = ary[i]; if (item.length < max) { break; } res.push(item.substring(0,1));}console.log(`出现次数最多的字母是:${res},出现了${max}次`)
C-从最大到最小找:
let str = 'webwangchengbinnxxxx', max = 0, res = [], flag = false;str = str.split('').sort( (a, b) => a.localeCompare(b)).join('');console.log(str); //abbceegghinnnnwwxxxxfor (let i=str.length; i>0; i--) { // /([a-zA-Z])\1{i-1}/ 两个斜杠之间的都是元字符,如果想把变量的值作为正则的一部分,我们只能用new RegExp() 这种方式 let reg = new RegExp('([a-zA-Z])\\1{'+(i-1)+'}','g'); // 在字符串中一个斜杠表示的是转义的意思,两个斜杠才是斜杠的意思 // ==> 上面的正则就是有一个字母,然后重复出现指定次数 str = str.replace(reg, (content,$1) => { res.push($1); max = i; flag = true; }); // 只要能够进入这个函数,就应该结束循环,所以我们再定义一个变量 if (flag) break;}console.log(`出现次数最多的字母是:${res},出现了${max}次`); //出现次数最多的字母是:n,x,出现了4次
案例五:时间字符串格式化
比如:
从服务器获取的格式:
'2019-11-19 15:39:5'
'2019/11/19 15:39:5'
想要转化为:
11月19日 15时39分
2019年11月19日
~ function () { // formatTime 时间字符串的格式化处理方法 function formatTime() { // 1-首先获取事件字符串中的年月日等信息 let timeAry = this.match(/\d+/g); // 因为调用的时候是 time.formatTime()这种形式, 所以this就是我们的 formatTime let template = '{0}年{1}月{2}日 {3}时{4}分{5}秒'; template = template.replace(/\{(\d+)\}/g, (content, $1) => { // => content: 当前本次大正则匹配的信息 // => $1: 本次小分组单独匹配的信息 // 以$1的值作为索引,到timeAry中找到对应的时间 let time = timeAry[$1] || '00'; // 如果没有时分秒 那么我们会得到undefined,这个时候我就用 00 表示 time.length 2 ? time = return time; }); return template; } // 扩展到内置类 String.prototype上 如果扩展的比较多的话就这么写,否则就按照正常的扩展就行了 ['formatTime'].forEach(item => { // String.prototype['formatTime'] = 'formatTime' // 右边的不能是字符串必须是个方法才可以,所以用eval转化一下 String.prototype[item] = eval(item); }); }();let time = '2019-11-19 15:39:5';console.log(time.formatTime()); //2019年11月19日 15时39分05秒
看起来很完美对吗?但是现在输出的格式是固定的,我们希望这个格式可以由用户来控制。如果这个格式用户没有传递,那么我们就使用默认的这个固定格式。
~ function () { /* @params: template: [string] 我们最后期望获取的日期格式的模板 模板规则: {0}=>年 {1}=>月 {2}=>日 {3}=>时 {4}=>分 {5}=>秒 @return [string]格式化后的时间字符串 by WangYuxi on 2019/11/19 */ function formatTime(template = '{0}年{1}月{2}日 {3}时{4}分{5}秒') { let timeAry = this.match(/\d+/g); return template = template.replace(/\{(\d+)\}/g, (...[, $1]) => { let time = timeAry[$1] || '00'; return time.length < 2 ? '0' + time : time; }); } ['formatTime'].forEach(item => { String.prototype[item] = eval(item); });}();let time = '2019-11-19 15:39:5';console.log(time.formatTime()); //2019年11月19日 15时39分05秒console.log(time.formatTime('{1}月{2}日 {3}:{4}')); //11月19日 15:39console.log(time.formatTime('{1}-{2} {3}:{4}')); //11-19 15:39console.log(time.formatTime('{0}年{1}月{2}日')); //2019年11月19日time = '2019-11-19';console.log(time.formatTime()); //2019年11月19日 00时00分00秒
案例六:对url地址进行处理:
~function() { /* queryURLParams: 获取URL地址问号后面参数的值,(可能也包含hash值) @params: @return: [object] 把所有参数以键值对的方式存储起来并且返回 */ function queryURLParams() { let obj = {}; this.replace(/([^?=]+)=([^?=]+)/g, (...[, $1, $2]) => obj[$1] = $2); this.replace(/#([^?=]+)/g, (...[,$1]) => obj['HASH'] = $1); return obj; } ['formDate','queryURLParams'].forEach( item => { String.prototype[item] = eval(item); })}(); let time = '2019-11-19 19:22:3';console.log(time.formDate());let url = 'http://www.cos.cn/?lx=1&from=wx#video';// ==> {lx:1,form:'wx',hash:'video'}console.log(url.queryURLParams()); //{lx: "1", from: "wx", HASH: "video"}
案例七:千分符
A- 不用正则:把字符串倒过来处理
let num = '1123456789'; //'1,123,456,789' 千分符num = num.split('').reverse().join('');for (let i=2; i-1; i+= let prev = num.substring(0, i+1), next = num.substring(i+1); num = prev + ',' + next;}num = num.split('').reverse().join('');console.log('===>', num); // ===> 1,123,456,789
B-正则:
~function() { /* millimeter: 实现大数字的千分符处理 @params @return [string] 千分符后的字符串 */ function millimeter() { return this.replace(/\d{1,3}(?=(\d{3})+$)/g, content => content + ','); } ['formDate', 'queryURLParams', 'millimeter'].forEach( item => { String.prototype[item] = eval(item); })}();let num = '1123456789'; //'1,123,456,789' 千分符console.log(num.millimeter());
吐血吗?正则会这么多,可以满足你日常工作和面试大部分的需求了。
相信能看到这里的人也很少。随意随意:-)