# 1、正则表达式的常用方法

# 1、test

  验证字符串是否符合某个规则。

# 2、exec

  用于捕获字符串中的字符

# 2、创建字符串的两种方式

# 1、字面量

  正则表达式中的部分内容是变量存储的值。两个斜杆中间包起来的都是元字符。不能在正则表达式中拼接变量。

const reg=/\d+/;
let type="james";
const reg2=/^@"+type+"@$/;//这里的"+表示匹配"一次或多次
console.log(reg2.test("@james@"));//false
const reg3=new Regexp("@"+type+"@");
console.log(reg3.test("@james@"));//true

1
2
3
4
5
6
7

# 2、构造函数

  构造函数因为传递的是字符串,""需要写两个斜杆。

//验证数字
const reg1=/\d+/;
const reg1=new Regexp("\\d+");//"\"需要写两个才代表斜杆
1
2
3

# 3、正则表达式的组成

  正则表达式由两部分组成,元字符修饰符

# 1、元字符

常用的元字符

# 1、量词元字符:设置出现的次数。

    • 零到多次
    • 1到多次
  • ?0次或者1次
  • {n} 出现n次
  • {n,} 出现n到多次
  • {n,m} 出现 n 到 m次

# 2、特殊元字符:单个或者组合在一起代表特殊额含义

  • \ 转义字符(普通->特殊->普通)。
  • . 除\n(换行符)以外的任意字符。
  • ^ 以哪一个元字符作为开始
  • $ 以哪一个元字符作为结束
  • \n 换行符
  • \d 0~9之间的数字
  • \D 非0~9之间的一个数字
  • \w 数字、字母、下划线之间的任意一个字符 [a-zA-Z0-9_]
  • \s 一个空白字符(包含空格、制表符、换行符)
  • \t 制表符(一个TAB键,四个空格)
  • \b 匹配一个单词的边界
  • x|y x或者y中的一个字符
  • [xyz] x或者y或者z中的一个字符
  • [^xy] 除了x/y以外的字符
  • [a-z] 指定a-z这个范围中的任意字符
  • () 正则中的分组
  • (?😃 只匹配不捕获
  • (?=) 正向预查
  • (?!) 负向预查

# 3、普通元字符:代表本身含义

# 4、元字符详解

  • ^.$
let reg1=/^\d/;//以数字开头
let reg2=/\d$/;//以数字结束
let reg3=/^\d+$/;//只能是数字
//验证手机号码 
let reg4=/^1\d{10}$/
1
2
3
4
5
  • \
let reg=/^2.3$/;//2和3之间可以是除\n之外的任意字符
let reg2=/^\\d/;//匹配以\d开始的字符串
const reg3=RegExp("\\d");
1
2
3
  • x|y 直接x|y会存在很乱的优先级问题 ,一般写的时候都伴随着小括号进行分组,因为小括号改变处理的优先级
let reg1=/^(18|29)$/;
console.log(reg.test("18"));//true
console.log(reg.test("29"));//true
console.log(reg.test("128"));//false 不加()时为true
console.log(reg.test("189"));//false 不加()时为true

1
2
3
4
5
6
  • [] 括号中出现的都是本身的意义。中括号中不存在多位数。
let reg=/^[@+]$/;
let reg2=/^[\d]$/;//匹配数字
reg2.test("9");//true
let reg3=/^[10-29]$/;//匹配的是1,0-2,9
1
2
3
4

# 5、常用的正则表达式

  • 1、验证是否是有效数字
/*
*规则分析
+1、可能出现 + - 号 [+-] 
+2、一位数0-9都可以,多位首位不能为0 (\d|([1-9]\d+))
+3、小数部分可能有可能没有,一旦有后面必须有小数点+数字 (\.\d+)?
*/
let reg=/^[+-]?(\d|([1-9]\d+))(\.\d+)$/;
1
2
3
4
5
6
7
  • 2、验证密码
//=>数字、字母、下划线
//=>6~16位
let reg=/^\w{6,16}/;
1
2
3
  • 3、验证真实姓名的
/*
+ 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}$/;

1
2
3
4
5
6
7
  • 4、验证邮箱
//\w+((-\w+)|(\.\w+)) 开头是数字字母或下划线
let reg=/^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+(\.|-)[a-z0-9]+)*\.[A-Za-z0-9]+$/;
1
2
  • 5、身份证号码
/*
+ 1、一共18位
+ 2、最后一可能是X
+ 3、前面6位是 省市县,中间8位是年月日 最后4位 倒数第二位偶数是女,奇数是男
*/
let reg=/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|x)$/
reg.exec("430421199408011654");
1
2
3
4
5
6
7

# 2、修饰符

正则表达式常用的修饰符

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

# 4、正则捕获

  实现正则捕获的方法。实现正则捕获的前提是:当前正则要和字符串匹配,如果不匹配的话,结果是null

  • 正则RegExp.prototype上的方法
    • exec
      • 捕获到的结果是null或者数组。
      • 数组第一项是本次捕获到的内容。其余项是对应小分组本次单次捕获的内容。
      • index是当前捕获内容在字符串中的起始索引。
      • input是原始字符串。
      • 每执行一次,只能捕获到一个符合正则规则的,但是默认情况下,获取到的结果永远是第一个匹配到的。这是正则捕获的懒惰性。原因是因为默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找。
      • 设置全局匹配符后后,lastIndex会自己修改。
      • 当全部捕获后,再次获取后的结果是null,但是lastIndex又回归为0
      //全部获取的实现
      function execAll(str=""){
          let arr=[],res=this.exec(str);
          if(!this.global) return res;
          while(res){
              arr.push(res[0]);
              res=this.exec(str);
          }
          return arr;
      }
      RegExp.prototype.execAll=execAll
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
    • test 加了全局修饰符后,基于test匹配后,lastIndex的值也会被修改。
  • 字符串String.prototype上支持正则表达式的方法。
    • replace
    • match
    const reg=/^\d+/g;
    "2018ddd2019ferwt2020".match(reg);//["2018","2019","2020"]
    
    1
    2
    • split
const reg1=/\d+/;
console.log(reg1.lastIndex);//0 当前正则下一次匹配的其实索引位置
const res=reg1.exec("2020afagsgsg1878787uu45");
1
2
3

# 1、正则的分组捕获

//身份证号码
let str="430431199404328765";
let reg=/^(\d{6})(\d{4})(\d{2})(\d{2})(\d)(?:\d|X)$/;
console.log(reg.exec(str));
console.log(str.match(reg));
//如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于"?:"来处理
1
2
3
4
5
6
//=>既要捕获到{数字},也想单独的把数字也获取到。
let str="{0}年{1}月{2}日";
let reg=/\{(d+)\}/;
console.log(reg.exec(str));//=>["{0}","0"...]
console.log(str.match(reg));//=>["{0}","0"...]
let reg1=/\{(d+)\}/g;
console.log(str.match(reg1));//=>["{0}","{1}","{2}"];在多次匹配的情况下,match只能捕获大正则匹配的内容获取到,小分组匹配的信息无法获取。
function match(str){
    const arrBig=[],arrSmall=[];
    const reg=/\{(d+)\}/g;
    let res=reg.exec(str);
    while(res){
        const [big,small]=res;
        arrBig.push(big);
        arrSmall.push(small);
        res=reg.exec(str);
    }
    return {
        arrBig,arrSmall
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//分组的第三个作用:"分组引用"
const str="book";//=>good look moon foot
let reg=/^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/;//=>分组引用就是通过"\数字"让其和对应分组出现一模一样的内容
1
2
3

# 2、正则捕获的贪婪性

  默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的。

let str="james2019@2020tj";
let reg=/\d+/g;
console.log(str.match(reg));["2019","2020"]//=>在量词元字符后面设置?:取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)。
let reg1=/\d+?/g;
console.log(str.match(reg));["2","0","1","9","2","0","2","0"];
1
2
3
4
5
6

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

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

# 3、其他正则捕获的方法

# 1、test也能捕获(本意是匹配)

let str="{0}年{1}月{2}日";
let reg=/\{(d+)\}/;
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" 存储的是上一次捕获的结果
//=>RexExp.$1~RegExp.$9:获取当前本次正则匹配后,第一个到第九个分组的信息
1
2
3
4
5
6
7
8
9
10
11

# 2、replace字符串中实现替换的方法(一般都是伴随正则一起使用的)

let str="jamestang2020@james2021";
str=str.replace(/([a-z]+)/g,"jie");//将jamestang james都替换成jie
1
2
//将时间字符串进行处理
let time="2020-12-21";//=>2020年12月21日
let reg=/^(\d{4})-(\d{1,2})-(\d{1,2})/;
time=time.replace(reg,"$1年$2月$3日");
console.log(time);//2020年12月21日
1
2
3
4
5

[str].replace([reg],[function])

  • 首先拿regtime进行匹配捕获,能匹配到几次就会把传递的函数执行几次(而且是匹配一次就执行一次)。
  • 不仅把方法执行,而且replace还给方法传递了实参信息(和exec捕获的内容一致的信息:大正则匹配的内容,小分组匹配的信息)
  • 在函数中我们返回的是什么,就把当前大正则匹配到的内容替换成什么
time=time.replace(reg,(big,$1,$2,$3)=>{
    //$1,$2,$3是定义的形参
    console.log(big,$1,$2,$3);//=>2020-12-21 2020 12 21
})
time=time.replace(reg,(big,...arg)=>{
   const [$1,$2,$3]=arg;
   $2.length<2?$2="0"+$2:null;
   $3.length<2?$3="0"+$3:null;
   return $1+"年"+$2+"月"+$3+"日"
})
1
2
3
4
5
6
7
8
9
10

# 5、实例

# 1、单词首字母大写

let str="good good study, day day up!";
let reg=/\b([a-zA-Z])[a-zA-Z]*\b/g;
str=str.replace(reg,(...arg)=>{
    let [content,$1]=arg;
    $1=$1.toUpperCase();
    content=content.subString(1);
    return $1+content;
})
1
2
3
4
5
6
7
8

# 2、验证一个字符串中哪个字母出现的次数最多,多少次?

//方法1 排序+正则
let str="dsafsdgdgewrwrwety";
str=str.split("").sort((a,b)=>a.localeCompare(b)).join("");
let reg=/([a-zA-Z]\1+)/g;//出现次数大于1的字符
let arr=str.match(reg);
arr.sort((a,b)=>b.length-a.length);
let max=arr[0].length,res=[res[0].subStr(0,1)];
for(let i=1;i<arr.length;i++){
    const item=arr[i];
    if(item.length<max>){
        break;
    }
    res.push(item.subStr(0,1))
}
//方法 2
let str="dsafsdgdgewrwrwety";
str=str.split("").sort((a,b)=>a.localeCompare(b)).join("");
let max=0,res=[],flag=false;
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) return break;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 3、时间字符串格式化、获取URL地址问号后面的参数信息、实现大数字的千分符处理

~function (){
    /**
     * formatTime:时间字符串格式化处理
     */
    function formatTime(template="{0}年{1}月{2}日{3}时{4}分{5}秒"){
        /**
         * 1、获取时间字符串中的年月日信息
         */
       const timeArr= this.match(/\d+/g);
       return template.replace(/\{(\d+)\}/g,(...[,$1])=>{
            let time=timeArr[$1]||"00";
            time.length<2?time="0"+time:null;
            //返回大正则匹配的内容
            return time;
       });
    }
    /**
     * 获取URL地址问号后面的参数信息
     * @return 把所有问号参数信息以键值对的方式存储起来并且返回
     */
    function queryURLParams(){
        let obj={};
        this.replace(/([^?=#&])=([^?=#&])/g,(...[,$1,$2])=>obj[$1]=$2)
        thia.replace(/#([^?=#&])/g,(...[,$1])=>obj["HASH"]=$1)
        return obj;
    }
    /**
     * 实现大数字的千分符处理
     */
    function millimeter(){
        return this.replace(/\d{1,3}(?=(\d{3}))+$/g,content=> content+",")
    }
    ['formatTime',"queryURLParams","millimeter"].forEach(item=>{
        String.prototype[item]=eval(item);
    })
}()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Last Updated: 12/27/2020, 3:10:55 PM