J53 正则

324 阅读10分钟

1.正则表达式

regular expression:简写 RegExp

  • 1.用来处理字符串的规则
  • 2.正则表达式用来处理字符串规则: 只能处理字符串
  • 3.它是一个规则:
    • 可以验证字符串是否符合某个规则(test),
    • 也可以把字符串中符合规则的内容捕获到(exec/match...)

1.学正则就是用来制定规则的(是否包含数字)

//1.字符串中没有出现数字
let str = "good good study,day day up!";
let reg = /\d+/;//=>出现0到多个数字
console.log(reg.test(str));
//=>false(str里面没有出现任何的数字,哪怕是出现了一个1,都没有)

//2.出现了一次数字 就是true
let str = "good 123good study,day day up!";
let reg = /\d+/;//=>出现0到多个数字
console.log(reg.test(str));
//=>true(str里面出现了数字,哪怕是出现了一个1,都是true)

2.也可以把字符串中符合规则的内容捕获到 (exec/mach...)

let str = "good 123good study,day day up!";
let reg = /\d+/;
    str = '2019-08-06';
console.log(reg.exec(str));//=>["2019", index: 0, input: "2019-08-06", groups: undefined]

3.控制台可以输出 dir(RegExp) 会查看到原型prototype会有test exec两个查看是否符合规则或者是否捕获到的方法

2.编写正则表达式

创建方式有两种

  • 1.字面量创建方式(两个斜杠之间包起来的,都是用来描述正则规则的元字符)
let reg1=/\d+/;
  • 2、构造函数模式创建两个参数:元字符字符串,修饰符字符串
let reg2=new RegExp('\\d+');

3.正则表达式由两部分组成:元字符、修饰符

  • 1、常用的元字符-——量词元字符:设置出现的次数
*     零到多次
+     一到多次
?     零次或者一次
{n}   出现n次
{n,}  出现n到多次
{n,m} 出现n到m次


//例子:
\d  :09的一个数字
\d* :0到多次连续的数字
\d+ :0到多次
\d? :01次
\d{5}:一个5位数
\d{5,}:5位或者5位以上的数字
 \d{5,10}:5位数到10位数
  • 2、特殊元字符:单个或者组合在一起代表特殊的含义
. : 除\n(换行符)以外的任意字符 
.+ : 除\n以外 1到多个的任意字符
 \ : 转义字符(普通=>特殊=>普通)
 ^ : 以哪个元字符开始
 $ : 以哪个元字符结束
 \n: 换行符   
 \d: 0-9之间的一个数字
 \D: 非0-9之间的数字,(大小写正好是相反的)
 \w: 数字、字母、下划线任意一个字符
 \s:一个空白符(包含空格 制表符 换页符)
 \t: 一个制表符(一个tab,四个空格)
 \b: 匹配单词的边界
x|y: x或者y中的一个字符    1|91或者9任意字符)   1|5|91或者5或者9任意字符)
[xyz]:x y z中的任意一个字符  [ablcsd3725]这堆中的任意一个字符
[^xy]:除了xy以外的任意字符
[a-z]:指定a-z这个范围的任意字符  例如下:[0-9a-zA-Z]:0-9中的任意一个字符,a-z中的任意一个字符,A-Z中的任意一个字符或者_    [0-9a-zA-Z]===\w
[^a-z]:不是以a-z开始的字符
():正则中的分组符号
(?:):只匹配不捕获
(?=):正向预查
(?!):负向预查  
  • 3、特殊元字符:单个或者组合在一起代表特殊的含义
/zhangsan/ 此正则匹配的就是‘zhangsan’
  • 4.修饰符

常用的修饰符:img

i => ignoreCase   忽略单词大小写匹配
m => multiline   可以进行多行匹配
g => global      全局匹配

//例子:
/A/.test("lalala")//=>false(这里的a是小写,所以没有大写A就返回false)

/A/i.test("lalala")//=>true(a 但是i是忽略大小写的 )

4.元字符详细解析

1.开始(^ $)都不加:正则规则是\d 0到9之间的数字,字符串中出现数字就可以

//0-9之间的数字
let reg=/\d/;

//(reg中是\d 0到9之间的数字 这是规则,而字符串中没有数字)
console.log(reg.test("zhangsan"));//=>false  

console.log(reg.test("2020zhangsan"));//=>true 

console.log(reg.test("zhangsan2019"));//=>true 

2.以数字结尾 $

//以数字结尾
let reg=/\d$/;

//reg中是\d$ 以0到9之间的数字结尾规则,而字符串结尾没有数字
console.log(reg.test("zhangsan"));//=>false

//这个是以数字开始,而结尾没有出现任何数字
console.log(reg.test("2020zhangsan"));//=>false 

console.log(reg.test("zhangsan2019"));//=>true 

3.^ $两个都不加:字符串中包含符合规则的内容即可

//(0-9之间的数字出现1到多次)
let reg=/\d+/; 

4.^ $两个都加,字符串只能是和规则一致的内容

 let reg=/^\d+$/;//(以数字开始,以数字结尾)

5.举个例子:验证手机号码

 //分析:手机号码是11位数字,以1开始 10个数字结束
 let reg=/^1\d{10}/;

5.(/)转义字符

  1. ^ . $ 三个字符制定规则
 //(以2开始  点是中间任意字符除换行以外 以3结尾)
let reg=/^2.3$/;
console.log(reg.test("2@3"));//=>true

console.log(reg.test("2.3"));//=>true

//(以数字2开始 3结尾中间没有任何字符,规则是中间可以出现任何字符)
console.log(reg.test("23"));//=>false 
  1. 基于转义字符,让其只能代表小数点
//(以2开始 中间出现点 以3结尾)
reg =/^2\.3$/;

console.log(reg.test("2.3"));//=>true

//(以2开始,3结尾  但是中间没有出现点 所以是false)
console.log(reg.test("23"));//=>false 
  1. 正则/d的输出
 //(单纯的字符串 'd')
let str='\d';

//(0到9开始   0-9 结尾)也就是数字开始  数字结尾
let reg=/^\d$/;

//字符串'd' 没有符合reg的规则  所以是false
console.log(reg.test(str));//=>false 
  1. 转义为 \d
let str='\\d';//=>\d的意思

let reg=/^\\d$/;//=>\d的意思

console.log(reg.test(str));//=>true

5.控制台输出

'张三\n李四' //=>'张三
            // 李四'
'张三\\n李四' //=>'张三\n李四'

6.x|y

  1. x|y
let reg= /^18|29$/;

console.log(reg.test('18'));//=>true (以18或29 任何一个)
console.log(reg.test('29'));//=>true
console.log(reg.test('129'));//=>true (以1开头 中间是8或者2 以9结尾)
console.log(reg.test('189'));//=>true  
console.log(reg.test('1829'));//=>true (以1、8开头 或 以2、9结尾)
console.log(reg.test('829'));//=>true
console.log(reg.test('182'));//=>true 

2.直接x|y会存在很乱的优先级为题,一般我们伴随着小括号进行分组,因为小括号改变处理的优先级=>小括号分组

reg=/^(18|29)$/;
console.log(reg.test('18'));//=>true
console.log(reg.test('29'));//=>true
console.log(reg.test('129'));//=>false(是以18开始或者29结束,都可以  而129不符合)

7.[]

1.中括号出现的字符一般都代表本身的含义

let reg=/^[@+]$/;//(以@或+开始或者结尾的意思)

console.log(reg.test('@'));//=>true
console.log(reg.test('+'));//=>true

//这里是两个@,因为中括号里面出现的是本身的意思,+不是多次的意思
console.log(reg.test('@@'));//=>false

//@或+开始或者结尾,不能同时出现
console.log(reg.test('@+'));//=>false

2.\d在中括号还是0-9

 reg=/^[\d]$/;//=>\d在中括号还是0-9
 
console.log(reg.test('d'));//=>false (此字符串中没有出现数字)
console.log(reg.test('\\'));//=>false (此字符串中没有出现数字)
console.log(reg.test('9'));//=>true

3.中括号不存在多位

reg=/^[18]$/;//(以1或8开始或者结束)

console.log(reg.test('1'));//=>true
console.log(reg.test('8'));//=>true
console.log(reg.test('18'));//=>false

4.中括号中不存在多位数

reg=/^[10-29]$/;//(1或 0到2 或9)

console.log(reg.test('1'));//=>true
console.log(reg.test('9'));//=>true
console.log(reg.test('0'));//=>true
console.log(reg.test('2'));//=>true
console.log(reg.test('10'));//=>false(中扩中不存在多位数)

8.验证是否为有效数字

 //规则分析:
//1.可能出现 + -号,也可能不出现.    [+ -]?
//2.一位0-9都可以,多位首位不能为0   [\d(1-9)\d+]
//3.小数部分可能没有,一旦有后面必须有小数点+数字   (\.\d+)?

let reg=/^[+-]? (\d([1-9]\d+))(\.\d+)?$/;

9.验证输入的用户名是否为有效

  • 1.正则写法
//分析:
//1.数字、字母、下划线   /w
//2. 6-16位

let val=userpassInp.value;
let reg=/\w{6,16}$/;
let flag=reg.test(val);
  • 2.js原生写法
let val=userpassInp.value;
function checkpass(val){
if(val.length<6 || val.length>16){
    alert('长度必须是6-16位之间!');
    return;
}
let area=['a','b',...'_'];//=>包含数字、字母、下划线
for(let i=0;i<val.length;i++){
  let char=val[i];
  if(!area.includes(char)){
      alert("格式不正确");
      return;
  }
}
}

10.验证真是姓名

//分析:
//1、汉字     /^[\u4E00-\u9FA5]$/
//2.名字的长度2~10;
//3.可能有译名·汉字 ([\u4E00-\u9FA5]{2,10})  {0,2}  (点不出现或者出现两次)

let reg=/^([\u4E00-\u9FA5]{2,10})(·[\u4E00-\u9FA5]{2,10}){0,2}$/; 

11.验证邮箱的正则

 let reg=/^\w+((-\w)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;

//分析
//1.开头是数字、字母、下划线 (1到多位)
//2.还可以是_数字字母下划线或者数字 字母下划线,整体零到多次
//=>邮箱的名字是由"数字、字母、下划线、- ·"几部分组成的,但是 - · 不能连续出现,也不能作为开始
//         \w((-\w)|(\.\w+))

//3.后面紧跟着数字、字母(1到多位)
   // @[A-Za-z0-9]+

//4.对@后面的补充
//多域名 .com.cn 
// 企业邮箱 zxt@zhufeng-peixun-office.com
// ((\.|-)[A-Za-z0-9]+)*

//5.这个匹配的是最后域名(.com/.cn/.org/.edu/.net...)
// \.[A-Za-z0-9]+

12.身份证号的正则

 //分析:简写
//1.一共18位
//2.最后一位可能是x(代表10)
let reg=/^\d{17}(\d|X)$/;

//分析:详细版
//1.身份证前六位:省市县 130828
//2.中间八位:年月日
//3、最后四位:最后一位可能是X 倒数第二位=>偶数 女 奇数 男  其余都是经过算法算出来的

//捕获的结果是数组,包含每一个小分组单独获取的内容
let reg=/^({\d{6}})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/;
reg.exec("130828199012040617");//=>["130828199012040617",'130828',"1990","12","04","1","7"...]

// 小括号分组的第二个作用:分组捕获,不仅可以把大正则匹配的信息捕获到,还可以单独捕获到每个小分组的内容

13.正则的两种创建方式的区别

构造函数因为传递的是字符串,\需要写两个才代表斜杠

//1.普通的创建正则的方式
let reg=/\d+/g;

//2.构造函数的创建方式
let reg=new.RegExp('\\d'+'g');

14.正则表达式是中间的部分内容是变量存储的值

  • 1.两个斜杠中间包起来的都是元字符(如果正则中要包含某个变量的值,则不能使用字面量的方式创建)
let type='zhangsan';
reg=/^@"+type+"@$/;//("可以出现多次,e可以出现多次)
console.log(reg.test("@zhangsan@"));//=>false
console.log(reg.test('@"""typeeeee"@'));//=>true
  • 2.这种情况只能使用构造函数方式(因为它传递的规则是字符串,只有这样子才能进行字符串拼接)
reg=new RegExp("^@+type+@$");
console.log(reg.test("@zhangsan@"));//=>true

15.实现正则捕获的方法

  • 1.正则RegExp.prototype上的方法:exec test
  • 2.字符串string.prototype上支持正则表达式处理的方法:replace match splice

1.exec把数字都捕获到

let str="zhangsan2019yangfan2020qihang2021";

let reg=/\d+/;
console.log(reg.exec(str));
//=>["2019",index:7,input:"zhangsan2019yangfan2020qihang2021"]

2.基于exec实现正则的捕获

  • 1.捕获到的结果是null或一个数组
    • 第一项:本次捕获到的内容
    • 其余项:对应小分组本次单独捕获到的内容
    • index:当前捕获内容在字符串中的起始索引
    • input:原始字符串
  • 2.每执行一次exec,只能捕获到一个符合正则规则的
//实现正则捕获的前提是:当前正则要和字符串匹配,如果不匹配捕获的结果是null
let str="zhangsan2019yangfan2020qihang2021";

//(0-9之间的数字可以任何字数开始或结束,中间可以出现多次规则)
let reg=/^\d+$/;

console.log(reg.test(str));//=>false (str中包含字母所以不符合规则)

console.log(reg.exec(str));//=>null 

3.reg.lastIndex:当前正则上下文下一次匹配的起始索引位置

  • 1.懒惰性捕获的原因:默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远只是第一个
  • 2.解决办法:全局修饰符g
let str="zhangsan2019yangfan2020qihang2021";
let reg=/\d+/;

//下面匹配捕获是从str索引零的位置开始查找
console.log(reg.lastIndex);//=>0 

console.log(reg.exec(str));
//第一次匹配捕获完成,lastIndex没有改变,所以下一次exec依然是从字符串最开始找,
//找到的永远是第一个匹配到的
console.log(reg.lastIndex);//=>0 

let reg=/\d+/g;
console.log(reg.exec(str));//=>[2019....]
//设置全局匹配修饰符g后,第一次匹配完  lastIndex会自己修改
console.log(reg.lastIndex);//=>11
console.log(reg.exec(str));//=>[2020....]
console.log(reg.lastIndex);//=>22
console.log(reg.exec(str));//=>[2021....]
console.log(reg.lastIndex);//=>32
console.log(reg.exec(str));//=>null

console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));//=>[2019....]又从0开始循环

let reg=/\d+/g;
if(reg.test(str)){
    //验证一下:只有正则和字符串匹配我们在捕获
    //基于test匹配验证后lastIndex已经被修改为第一次匹配后的结果,
    //所以下一次捕获不在从头开始
    console.log(reg.lastIndex);//=>11
    console.log(reg,exec(str));//=>[2020....]
}

4.编写一个execAll,执行一次可以把所有匹配的结果捕获到(前提正则一定设置全局修饰符g)

~function execAll(){
function exec(str=""){
    //str:要匹配的字符串
    //this:RegExp的实例(当前操作的正则)
    //=>进来后第一件事,是验证当前正则是否设置了g,不设置则不能在进行循环捕获了,否则会导致死循环
    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;
}
RegExp.prototype.execAll=execAll;
}();
let str='zhangsan2019yangfan2020qihang2021';
let reg=/\d+/g;
console.log(reg.exec(str));//=>[2019,2020,2021]

5.字符串的match方法,可以在执行一次的情况下捕获到所有匹配的数据(前提是正则也得设置g才可以)

let reg=/\d+/g;
console.log("张三2020@2019李四".match(reg));//=>["2020", "2019"]
console.log('zhangsan2019yangfan2020qihang2021'.match(reg))
;//=>["2019", "2020", "2021"]

16.正则的分组捕获

  • 1.身份证号码分组捕获
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"]
//=>第一项:大正则匹配的结果
//=>其余项:每一个小分组单独匹配捕获的结果
//=>如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于?:来处理
  • 2.既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到 {0} 还需要单独获取0
//1.正则分组捕获的方法
let str = "{0}年{1}月{2}日";

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

let reg = /\{(\d+)\}/;
console.log(reg.exec(str));
console.log(str.match(reg));
//["{0}", "0",...]
//2.封装一个方法,大正则、小分组的捕获方法
let str = "{0}年{1}月{2}日";
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"]
  • 3.分组的作用:1.改变优先级 2.分组捕获 3.分组引用
let str = "book"; //=>"good"、"look"、"moon"、"foot"...

let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/;
//=>分组引用就是通过“\数字”让其代表和对应分组出现一模一样的内容

console.log(reg.test("book")); //=>true
console.log(reg.test("deep")); //=>true
console.log(reg.test("some")); //=>false

let str="book";
let reg=/^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/;
console.log(reg.test("book"));//=>true
console.log(reg.test("soom"));//=>true
console.log(reg.test("deck"));//=>false

17.正则捕获的贪婪性

  • 1.默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
let str = "张三2019@2020李四";
let reg = /\d+/g;
console.log(str.match(reg)); //=>["2019","2020"]
  • 2.在量词元字符后面设置?:取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)
let str = "张三2019@2020李四";
let reg = /\d+/g;
reg = /\d+?/g;
console.log(str.match(reg));
//=>["2", "0", "1", "9", "2", "0", "2", "0"]

18.问号在正则中的五大作用:

  • 1.问号左边是非量词元字符:本身代表量词元字符,出现零到一次
  • 2.问号左边是量词元字符:取消捕获时候的贪婪性
  • 3.(?:) 只匹配不捕获
  • 4.(?=) 正向预查
  • 5.(?!) 负向预查

19.test也能捕获(本意是匹配)

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

  • 1.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" 存储的是上次捕获的结果
  • 2.exec
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g; 
console.log(reg.exec(str)); //=>["{0}", "0"...]
  • 3.test
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g; 

 // => TEST
// 每一次匹配也和捕获一样,受制于reg.lastIndex(前提也是设置了g修饰符,
//不设置g每一次还是从0开始查找,规则和捕获一样)
console.log(reg.lastIndex); //0
console.log(reg.test(str)); //true
console.log(reg.lastIndex); //3
console.log(reg.test(str)); //true
console.log(reg.lastIndex); //7
console.log(reg.test(str)); //true
console.log(reg.lastIndex); //11
console.log(reg.test(str)); //false
console.log(reg.lastIndex); //0

reg.test(str);
console.log(RegExp.$1); //=>0 
//获取当前本次匹配项中,第一个分组匹配的内容($1~$9代表正则中第几个分组中的内容);
//$&是获取当前大正则匹配的内容;

reg.test(str);
console.log(RegExp.$1); //=>1 

// 思维:在每一次捕获之前,先判断是否匹配,只有匹配再去捕获
let str = "zhangsan2020";

// 不设置G的情况下,不论TEST还是EXEC都是从索引零的位置开始查找(懒惰性)
let reg = /\d+/;
if (reg.test(str)) {
// console.log(reg.lastIndex); //=>0
console.log(reg.exec(str)); //=>["2020"]
}

// 如果取消了懒惰性,每一次TEST或者EXEC后,都会修改其lastIndex的值,
//导致下一次是在上一次匹配的末尾位置再次查找
reg = /\d+/g;
if (reg.test(str)) {
// console.log(reg.lastIndex); //=>11
console.log(reg.exec(str)); //=>null
} 

4.身份证信息捕获每个分组中的信息

let str = "130828199012040617";
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/; 

console.log(reg.exec(str)); 
//=>["130828199012040617", "130828", "1990", "12", "04", "1"...] 

console.log(reg.test(str)); //=>true
console.log(RegExp['$&']); //=>"130828199012040617"
console.log(RegExp['$1']); //=>"130828"
console.log(RegExp['$2']); //=>"1990"
console.log(RegExp['$3']); //=>"12"

20.ES6中新增的

  • 1.分组具名化(给分组起名字)?<名字>
  • 2.后期匹配完,可以基于匹配结果中的groups获取指定名字分组捕获的信息
reg = /^(?<A>\d{6})(?<B>\d{4})(?<C>\d{2})(?<D>\d{2})\d{2}(?<E>\d)(?:\d|X)$/;

let res = reg.exec(str);
console.log(res.groups.A);
console.log(res.groups.E); 

21.replace本身是字符串替换的意思

  • 1.再不使用正则的情况下,每一次执行REPLACE只能替换一个
let str = "zhangsan2020zhangsan2021"; //=>把"zhangsan"替换成为"张三"
str = str.replace('zhangsan', '张三');
str = str.replace('zhangsan', '张三');
console.log(str); //=>"张三2020张三2021" 

let str = "zhangsan2020zhangsan2021";
str = str.replace(/zhangsan/g, '张三');
console.log(str); //=>"张三2020张三2021" 
  • 2.很多需求不使用正则是无法解决的
//=>把"zhangsan"替换成为"zhangsannifei"
let str = "zhangsan2020zhangsan2021"; 

//1.replace是实现不了的
str = str.replace('zhangsan', 'zhangsannifei');
console.log(str); //=>"zhangsannifei2020zhangsan2021"

//=>还是从最新字符串索引为零的位置开始查找替换
str = str.replace('zhangsan', 'zhangsannifei'); 
console.log(str); //=>zhangsannifeinifei2020zhangsan2021 

//2.解决方案:正则
let str = "zhangsan2020zhangsan2021";
str = str.replace(/zhangsan/g, 'zhangsannifei');
console.log(str); //=>zhangsannifei2020zhangsannifei2021
// 3.方法的封装
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;

// STR=STR.REPLACE(REG,FUNC)
// 1.首先会拿REG和STR去进行匹配捕获,匹配捕获一次,就会把FUNC函数执行一次
// 2.并且会把每一次捕获的结果(和EXEC捕获的结果一样)传递给FUNC函数
// 3.FUNC函数中返回啥,就相当于把原始字符中,大正则匹配的结果替换成啥
str = str.replace(reg, (...args) => {
// console.log(args); => 存储的是每一次正则匹配捕获的结果
//[大正则匹配的、小分组匹配的、捕获的起始索引、原始字符串]

return '@@';
});
console.log(str); //=>"@@年@@月@@日"

22.把时间字符串进行处理

  • 1.replac替换
 let time = "2019-08-13";
 //=>变为"2019年08月13日"
   
let time = "2019-08-13";
let reg=/(\d{4})-(\d{1,2})-(\d{1,2})$/;
let time=time.replace(reg,'$1年$2月$3日');
console.log(time);
  • 2.[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);
});
*/


let time = "2019-08-13";

//编写一个正则符合上面的格式并且可以获取到字符串的
let reg=/(\d{4})-(\d{1,2})-(\d{1,2})$/;

//时间等于时间的模板,符合以上正则规则的接受
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+"日";
});

23.单词首字母大写

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!"

24.时间字符串的格式化处理

  • 1.formatTime:时间字符串的格式化处理
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>时间字符串格式化处理</title>
</head>
<body>
	<script>
		/*
		 * formatTime:时间字符串的格式化处理
		 *   @params
		 *     templete:[string] 我们最后期望获取日期格式的模板
		 *     模板规则:{0}->年  {1~5}->月日时分秒
		 *   @return
		 *     [string]格式化后的时间字符串
		 *      2019/08/13
		 */

		//1.方案一:formatTime
		String.prototype.formatTime = function formatTime(template) {
			// 1.根据操作的时间字符串获取年月日小时分钟秒等信息
			let arr = this.match(/\d+/g).map(item => {
				return item.length < 2 ? '0' + item : item;
			});

			// 2.解析格式化的模板,找到对应的时间,替换模板中的内容
			template = template || '{0}年{1}月{2}日 {3}时{4}分{5}秒';
			return template.replace(/\{(\d+)\}/g, (_, group) => {
				return arr[group] || "00";
			});
		};

		let time = "2019-8-13 16:51:3";
		console.log(time.formatTime());
		console.log(time.formatTime("{0}年{1}月{2}日"));
		console.log(time.formatTime("{1}-{2} {3}:{4}"));
		time = "2019/8/13";
		console.log(time.formatTime());
		console.log(time.formatTime("{0}年{1}月{2}日"));
		console.log(time.formatTime("{1}-{2} {3}:{4}"));


        //=>服务器获取的
        // "2019-8-13 16:51:3"
        // "2019/8/13 16:51:3"
        // "2019/8/13"
        //=>想要转变为的格式
        // "08月13日 16时51分"
        // "2019年08月13日"
        // "2019年08月13日 16时51分03秒"
	</script>
</body>
</html>
  • 2.match
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>时间字符串格式化处理</title>
</head>
<body>
	<script>
    //2.方案二:match
		let time = "2020-4-8";
		//=>变为"2020年04月08日"
		let arr = time.match(/\d+/g);
		arr = arr.map(item => item.length < 2 ? '0' + item : item);
		time = `${arr[0]}${arr[1]}${arr[2]}日`;
		console.log(time); //=>"2020年04月08日"
	</script>
</body>
</html>
  • 3.match正则处理方式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>时间字符串格式化处理</title>
</head>
<body>
<script>
//3.方案三

let time = "2020-4-8";

let arr = time.match(/\d+/g)
	.map(item => item.length < 2 ? '0' + item : item);
//arr=['2020','04','08']

let template = '{0}年{1}月{2}日';
// 思路:获取 {0}和0 ,基于索引0到arr中获取"2020",把得到的2020替换{0} =>{0}被替换为arr[0] ...

template = template.replace(/\{(\d+)\}/g, (value, group) => {
	// group小分组每一次匹配的结果
	// arr[group] 基于小分组捕获的索引到数组中找到对应的项
	return arr[group]; //=>返回啥就是把TEMPLETE中大正则本次匹配的结果替换成啥
});

console.log(template);
</script>
</body>
</html>

25.queryURLParams:正则处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>正则处理URL</title>
</head>
<body>
    <script>       
	/* 
	 * queryURLParams:获取URL地址问号和面的参数信息(可能也包含HASH值)
	 *   @params
	 *   @return
	 *     [object]把所有问号参数信息以键值对的方式存储起来并且返回
	 * by zhufengpeixun on 2019/08/13
	 */
	 String.prototype.queryURLParams = function queryURLParams() {
		let obj = {};
		this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, $1, $2]) => obj[$1] = $2);
		this.replace(/#([^?=&#]+)/g, (...[, $1]) => obj['HASH'] = $1);
		return obj;
	}

let url = "http://www.zhufengpeixun.cn/?lx=1&from=wx#video";

console.log(url.queryURLParams());
//=>{lx:1,from:'wx',HASH:'video'}
	</script>
</body>
</html>

26.千分符

  • 1.millimeter:实现千分符处理
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>千分符</title>
</head>
<body>
  <script>
		// millimeter:实现千分符处理
		String.prototype.millimeter = function millimeter() {
			let str = this.split('').reverse().join('');
			str = str.match(/\d{1,3}/g).join(',');
			return str.split('').reverse().join('');		
		};

		let str = "2312345638";
		str = str.millimeter();
		console.log(str); //=>"2,312,345,638"
	</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>千分符</title>
</head>
<body>
<script>
    ~function(){
    /* 
	* millimeter:实现大数字的千分符处理
	*   @params
	*   @return
	*     [string]千分符后的字符串
    */
function millimeter() {
	return this.replace(/\d{1,3}(?=(\d{3})+$)/g, content => content + ',');
}

["millimeter"].forEach(item => {
	String.prototype[item] = eval(item);
});
}();

let num = "15628954"; //=>"15,628,954" 千分符
console.log(num.millimeter());
num = "112345678256874"; //=>"112,345,678,256,874"
console.log(num.millimeter());
</script>
</body>
</html>

27.MATCH VS EXEC

字符串中和正则搭配实现正则捕获的方法 String.prototype

  • match
  • replace
  • split
  • 1.在设置全局修饰符G的情况下
    • EXEC每一次执只能捕获一个匹配的结果(当前结果中包含大正则和小分组匹配的结果),如果想要捕获全需要执行多次
    • MATCH执行一次就能把所有正则匹配的信息捕获到(只有大正则匹配的,并不包含小分组匹配的信息)
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.exec(str)); //=>["{0}", "0",...]
// ...
console.log(str.match(reg)); //=>["{0}", "{1}", "{2}"] 
  • 2.如果不设置G的情况下:都只能捕获到第一个匹配的结果,获取的结果一模一样
let str = "130828199012040617";
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;

console.log(reg.exec(str)); 
//=>["130828199012040617", "130828", "1990", "12", "04", "1",...]

console.log(str.match(reg)); 
//=>["130828199012040617", "130828", "1990", "12", "04", "1",...]