js正则限制字符串长度_正则笔记(3)万字长文,慎点。

68de7a671e9e63f40f18a7c9f8df9ac0.gif

正则讲了很久,也拖了很久,今天看看怎么用吧,后续更文应该会比较准勤快了。:-)

书接上文【正则笔记(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

937f7cf0e284cdf45394fb39f61a80ff.png

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());

吐血吗?正则会这么多,可以满足你日常工作和面试大部分的需求了。

相信能看到这里的人也很少。随意随意:-)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言深度剖析书籍学习记录 第四章 指针和数组

p 称为指针变量,p 里存储的内存地址处的内存称为 p 所指向的内存。 指针变量 p 里存储的任何数据都将被当作地址来处理一个基本的数据类型(包括结构体等自定义类型)加上“*” 号就构成了一个指针类型的模子。这个模子的大小是一定的&#xff0c;与“*”号前面的数据类型无 关。…

js中select下拉框重置_如何利用CSS3制作炫酷的下拉框

很多小伙伴都不清楚CSS3是做什么&#xff1f;用途是什么&#xff1f;接下来我就给展示一个css3制作一个炫酷下拉框。其实不只是这些&#xff0c;还有很多。CSS3是CSS(层叠样式表)技术的升级版本&#xff0c;于1999年开始制订&#xff0c;2001年5月23日W3C完成了CSS3的工作草案&…

select选择框必输校验_轮子这么多,我们为什么选择自研NewSQL

作者介绍李鑫&#xff0c;滴滴资深软件开发工程师&#xff0c;多年分布式存储领域设计及开发经验。曾参与NoSQL/NewSQL数据库Fusion、分布式时序数据库sentry、NewSQL数据库SDB等系统的设计开发工作。一、背景Fusion-NewSQL是由滴滴自研的在分布式KV存储基础上构建的NewSQL存储…

C语言深度剖析书籍学习记录 第五章 内存管理

常见的内存错误 定义了指针变量&#xff0c;但是没有为指针分配内存&#xff0c;即指针没有指向一块合法的内存。 结构体成员指针未初始化 很多初学者犯了这个错误还不知道是怎么回事。这里定义了结构体变量 stu&#xff0c;但是他没 想到这个结构体内部 char *name 这成员在定…

怎么改电脑网络ip地址_抛弃重启路由器获取ip地址方式,巧妙运用ip代理改IP工具...

网络是简单的也是复杂的&#xff0c;在如此庞大的网络世界里有太多的不确定因素&#xff0c;导致我们遇到IP限制问题&#xff0c;从而影响到我们的网络访问&#xff0c;而大家都知道&#xff0c;如果遇到ip被限制的问题&#xff0c;最快速直接的办法就是把被限制的ip更换一个新…

C语言深度剖析书籍学习记录 第六章 函数

函数的好处 1、降低复杂性:使用函数的最首要原因是为了降低程序的复杂性&#xff0c;可以使用函数来隐含信息&#xff0c;从而使你不必再考虑这些信息。2、避免重复代码段:如果在两个不同函数中的代码很相似&#xff0c;这往往意味着分解工作有误。这时&#xff0c;应该把两个…

如何把word分装到两个byte_如何核对两个Word文档的内容差别?同事加班半小时,我只花了30秒...

昨天下班前&#xff0c;老板突然发了两份Word文档过来&#xff0c;一份是原稿&#xff0c;还有一份是修订稿&#xff0c;叫我们找出两份文档的内容差别之处&#xff0c;我只花了30秒就搞定了&#xff0c;然后准时下班&#xff01;你想知道我是怎么操作的吗&#xff1f;下面小源…

stm32f767中文手册_ALIENTEK 阿波罗 STM32F767 开发板资料连载第五章 SYSTEM 文件夹

1)实验平台&#xff1a;alientek 阿波罗 STM32F767 开发板2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号&#xff0c;获取更多资料&#xff1a;正点原子第五章 SYSTEM 文件夹介绍第三章&#xff0c;我们介绍了如何在 MDK5 下建立 STM32F7 工程。在这个新建的工程之…

手机安卓学习 内核开发

官网开源代码 Documentation - MiCode/Xiaomi_Kernel_OpenSource - Sourcegraph Xiaomi 11T Pro GitHub - MiCode/Xiaomi_Kernel_OpenSource: Xiaomi Mobile Phone Kernel OpenSourceAndroid 开源项目 | Android Open Source Project google安卓官网 目录概览 参考…

vs 启动调用的目标发生异常_如何解决不可测、异常场景的问题?

阿里QA导读&#xff1a;在软件研发过程中&#xff0c;发布前跨多个系统的联调测试是不可或缺的一环&#xff0c;而在联调过程中&#xff0c;经常会遇到一些比较棘手的困难&#xff0c;阻塞整个联调进程。其中比较典型的有&#xff1a;第三方的研发节奏不一致&#xff0c;导致无…

Linux内核 scatterlist介绍

scatterlist 物理内存的散列表。通俗讲&#xff0c;就是把一些分散的物理内存&#xff0c;以列表的形式组织起来 诞生背景 假设有三个模块可以访问memory&#xff1a;CPU、DMA控制器和某个外设。CPU通过MMU以虚拟地址&#xff08;VA&#xff09;的形式访问memory&#xff1b;…

Linux内核 crypto文件夹 密码学知识学习

密码算法分类 对称算法非对称算法消息摘要&#xff08;单向哈希&#xff09;算法这些算法作为加密函数框架的最底层&#xff0c;提供加密和解密的实际操作。这些函数可以在内核crypto文件夹下&#xff0c;相应的文件中找到。不过内核模块不能直接调用这些函数&#xff0c;因为…

Linux crypto相关知识的汇总 Linux加密框架crypto中的算法和算法模式(一)

Linux加密框架中的算法和算法模式 Linux加密框架中的算法和算法模式&#xff08;一&#xff09;_家有一希的博客-CSDN博客 加密框架支持的密码算法主要是对称密码算法和哈希算法&#xff0c;暂时不支持非对称密码算法。除密码算法外&#xff0c;加密框架还包括伪随机数生成算法…

Linux crypto相关知识的汇总 Linux加密框架crypto对称算法和哈希算法加密模式

参考链接 Linux加密框架中的算法和算法模式&#xff08;二&#xff09;_家有一希的博客-CSDN博客 对称算法 分组算法模式 ECB模式 ECB模式下&#xff0c;明文数据被分为大小合适的分组&#xff0c;然后对每个分组独立进行加密或解密如下图所示如果两个明文块相同&#xff0c…

Linux加密框架中的算法和算法模式

参考链接 Linux加密框架中的算法和算法模式&#xff08;三&#xff09;_家有一希的博客-CSDN博客 对称算法 14 如上所示&#xff0c;在arc4.c中定义了两个与RC4算法相关的算法实现&#xff0c;分别为arc4和ecb(arc4)&#xff0c;其中arc4是RC算法的算法实现&#xff0c;而ecb…

Linux加密框架crypto AES代码相关

例子 aes_generic.c - crypto/aes_generic.c - Linux source code (v5.15.11) - Bootlin static struct crypto_alg aes_alg {.cra_name "aes",.cra_driver_name "aes-generic",.cra_priority 100,.cra_flags CRYPTO_ALG_TYPE_CIPHER,.cra_blocks…

Linux加密框架 crypto RC4

参考链接 arc4.h Linux加密框架中的主要数据结构&#xff08;一&#xff09;_家有一希的博客-CSDN博客 头文件 arc4.h - include/crypto/arc4.h - Linux source code (v5.15.11) - Bootlin实现代码 arc4.c arc4.c - crypto/arc4.c - Linux source code (v5.15.11) - Bootlin…

Linux加密框架 crypto 哈希算法说明 同步哈希shash_alg | 异步哈希 ahash_alg | 通用部分抽象 hash_alg_common

参考链接 Linux加密框架中的主要数据结构&#xff08;二&#xff09;_家有一希的博客-CSDN博客 定义 通用算法说明数据结构crypto_alg的联合体成员变量cra_u中包含多种算法的个性化属性&#xff0c;如分组算法、块加密算法、压缩算法、伪随机数算法等&#xff0c;但不包含哈希…

Linux加密框架 crypto 哈希算法举例 MD5

参考链接 Linux加密框架 crypto 哈希算法说明 同步哈希shash_alg | 异步哈希 ahash_alg | 通用部分抽象 hash_alg_common_CHYabc123456hh的博客-CSDN博客Linux加密框架中的主要数据结构&#xff08;二&#xff09;_家有一希的博客-CSDN博客 MD5 md5.h - include/crypto/md5.h …