JS中的正则表达式&&全面梳理|内附思惟导图

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE)javascript

用来处理字符串的规则html

  • 只能处理字符串
  • 它是一个规则:能够验证字符串是否符合某个规则(test),也能够把字符串中符合规则的内容捕获到(exec / match...)
let str = "good good study , day day up!";
//=>学正则就是用来制定规则(是否包含数字)
let reg = /\d+/;
reg.test(str); //=>false

str = "2020-04-07";
reg.exec(str); //=>["2020",index:0,inputs:"原始字符串"]
复制代码

1、正则基础(RegExp)

一、定义

定义:是一种处理字符串的规则java

  • JS中的正则 是一种引用数据类型

二、正则的编写方式

构造函数由于传递的是字符串,\须要写两个才表明斜杠es6

  • 字面量方式:let reg = /\d+/g;
  • 实例的方式:let reg = new RegExp("\\d+","g");
    • 当正则中的一些字符须要是变量的时候;才会选择这种方式

两种方式的区别

  • 正则表达式中的部份内容是变量存储的值时
//1.两个斜杠中间包起来的都是元字符(若是正则中要包含某个变量的值,则不能使用字面量方式建立)
let type = "xiaozhima";
reg = /^@"+type+"@$/; 
console.log(reg.test("@xiaozhima@")); //=>false
console.log(reg.test('@"""typeeeee"@')); //=>true

//2.这种状况只能使用构造函数方式(由于它传递的规则是字符串,只有这样才能进行字符串拼接)
reg = new RegExp("^@"+type+"@$");
console.log(reg.test("@xiaozhima@"));//=>true
复制代码

三、正则的用途

正则RegExp.prototype上的方法正则表达式

  • 匹配 test
  • 捕获 exec
  • 匹配 test
    • 编写一个正则(制定了一套规则):去测试某一个字符串是否符合这个规则;
  • 捕获 exec
    • 编写一个正则(制定了一套规则):去把某个字符串中符合这个规则的字符获取到

字符串String.prototype上支持正则表达式处理的方法数组

  • replace
  • match
  • splite
  • .......

四、正则的组成(只列举一些经常使用的)

正则表达式由一些修饰符和一些元字符(metacharacters)组成。markdown

  • 元字符则由普通字符和一些特殊字符组成:
    • 普通字符包括大小写的字母和数字,
    • 特殊元字符则具备特殊的含义,咱们下面会给予解释。

-1).修饰符

用在正则外边的:ide

  • 例如:/abc/i里的i
字符 含义 英文全称
i 忽略大小写 ignoreCase
m 多行匹配 multiline
g 全局匹配 global
s 让“点”能匹配任意字符,包含 \n 和 \r
...... ......

-2).元字符

斜杠中间的 内容 咱们称为元字符函数

  • 例如:/abc/i里的abc

普通元字符

就是普通的大小写的字母和数字;工具

特殊元字符

有特殊含义的元字符

字符 含义
\ 转义字符(把有特殊含义的字符转换成字符自己,也能够把普通字符转义成有特殊含义的字符)
\d 0~9之间的数字
\D 除了0~9 以外的任意字符
\w 数字、字母、下划线(小写w)
\W 除了 数字、字母、下划线 的任意字符(大写W)
^ 以什么字符开头
$ 以什么字符结尾
. 表明除了换行之外的全部字符
\n 表明换行
\s 一个空白字符(包含空格、制表符、换行符等)
\t 一个制表符(一个TAB键:4个空格)
\b 匹配一个单词的边界
---- ----
x|y 表明 或;x或y
[xyz] 表明 或;x或y或z (与上一个的区别是:[]中先后只能写单个字符,而|先后能够是一组数)
[^xy] 除了xy的任意字符
[a-z] a~z 的任意字符 小写的英文字母
[^a-z] 除了a-z 的任意字符
() 分组和提高优先级
(?:) 只匹配不捕获
(?=) 正向确定预查
(?!) 正向否认预查
...... ......

量词元字符

都是用在其余元字符后面的

  • 例如:/abc{3}/ => {3}
字符 含义
前面的字符出现 0 或者 1 次 便可
+ 前面的字符出现 1 次或 屡次 便可
* 前面的字符出现 0 或 屡次 便可
{n} 前面的字符连续出现 n 次 便可
{n,m} 前面的字符连续出现 n 到 m 次 便可
{n,} 前面的字符连续出现 n 到 屡次 便可
...... ......

思惟导图:正则基础

2、正则的匹配(test)

编写一个正则(制定了一套规则):去测试某一个字符串是否符合这个规则;

一、语法

  • 正则.test(字符串)

二、返回值

  • 符合正则规则:返回TRUE
  • 不符合正则规则:返回FALSE

三、一些例子🌰练习

\d,?,{n,m}的相关练习

var str = '小芝麻666';
var reg = /\d/; // 只要字符串中含有数字 便可
console.log(reg.test(str)) // true 
console.log(reg.test('werwf2ergdfg'))//true
console.log(reg.test('aefasdfsdfsf'))//false
console.log(reg.test('3453245254')) // true 

var reg = /\d?/; // 数字出现0或1次 字符串有没有数字都知足状况
console.log(reg.test('xiaozhima666')) // true
console.log(reg.test('werwf2ergdfg'))//true
console.log(reg.test('aefasdfsdfsf'))//true
console.log(reg.test('3453245254')) // true


var reg = /\d{2,4}/; // 字符串中有没有连续2个或者3个数字 或者4个数字
// /\d\d/ /\d\d\d/ /\d\d\d\d/
console.log(reg.test('xiaozhima666')) // true
console.log(reg.test('werwf2ergdfg'))//false
console.log(reg.test('aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 


var reg = /\d{2}/; // 字符串中 有两个连续的数字 便可
console.log(reg.test('xiaozhima666')) // true
console.log(reg.test('werwf2e3rgdfg'))// false
console.log(reg.test('aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 
复制代码

开头^ 和 结尾$ 的相关练习

  • 正则中有 ^ $ : 字符串必须所有知足正则
  • 正则中没有 ^ $ : 只要字符串中有符合这个正则的字符便可
var reg = /^\d/; // 要求字符串是 以数字开头的
console.log(reg.test('xiaozhima666')) // false
console.log(reg.test('werwf2e3rgdfg'))// false
console.log(reg.test('aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 


var reg = /^\d{2,3}/; // 要求 字符串 是以 两个或者三个数字开头的 便可
console.log(reg.test('1xiaozhima666')) // false
console.log(reg.test('22werwf2e3rgdfg'))// true
console.log(reg.test('432aefasdfsdfsf'))// true
console.log(reg.test('3453245254')) // true



var reg = /d{2,3}/; //字符串中 须要有连续两到三个d
console.log(reg.test('1xiaozhima666')) // false
console.log(reg.test('22werwf2e3rgdfg'))// false
console.log(reg.test('432aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // false


var reg = /\d$/; // 字符串须要是一个 数字 结尾的字符
console.log(reg.test('1xiaozhima666')) // true
console.log(reg.test('22werwf2e3rgdfg'))// false
console.log(reg.test('432aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 


var reg = /\d{4,6}$/; // 以4-6个数字结尾的字符串
console.log(reg.test('1xiaozhima666')) // false
console.log(reg.test('22werwf2e3rgdfg'))// false
console.log(reg.test('432aefasdfsdfsf3456'))// true
console.log(reg.test('3453245254')) // true 


// 正则中有 ^ $ 他就是说字符串必须所有知足正则
// 正则中没有 ^ $ 只要字符串中有符合这个正则的字符便可 
// var reg2 = /\d/;
var reg = /^\d$/; // 以数字开头 以数字结尾:以一个数字开头 还得以这个数字结尾
console.log(reg.test('432aefasdfsdfsf3456'))// false
console.log(reg.test('3453245254')) // false
console.log(reg.test('3333')) // false
console.log(reg.test('1')) // true
console.log(reg.test('9'))// true
console.log(reg.test('4'))// true
console.log(reg.test('5'))// true 
console.log(reg.test('8'))// true



var reg  = /^\d{2,3}$/;// 以两到三个数字开头 还得以这两到三个数字结尾 
// 也就是说 这个正则只能匹配 两到三位数字的字符串
console.log(reg.test('432aefasdfsdfsf3456'))// false
console.log(reg.test('3453245254')) // false
console.log(reg.test('3333')) // false
console.log(reg.test('1')) // false
console.log(reg.test('9'))// false
console.log(reg.test('4'))// false
console.log(reg.test('5'))// false
console.log(reg.test('8'))// false
console.log(reg.test('18'))// true 



var reg = /^\d+.\d{2}$/;
console.log(reg.test('123.345'))// false
console.log(reg.test('123r34')) // true
console.log(reg.test('1235345'))//true
console.log(reg.test('123r345')) // false
console.log(reg.test('123 345')) // false
console.log(reg.test('123r45')) // true 



var reg = /\\d+/;// 要去匹配一个 \ 后边是1到多个d字符 ‘\dd......’
console.log(reg.test('qqwewer'))// false
console.log(reg.test('134543'))// false
console.log(reg.test('134543d'))// false
console.log(reg.test('dd'))// false
console.log(reg.test('\dd'))// true
console.log(reg.test('\\dd')) //true
复制代码

中括号[ ]:或的相关练习

  • 中括号中出现的字符通常都表明自己的含义
    • [] 中的:量词元字符 | . 再也不具备特殊含义了;
    • \d在中括号中仍是0-9
  • [] 中的字符 ‘-’ 是按照 对应的的阿斯克码值对应的;
  • [] 中要是想让 ‘-’ 表明他本身:建议最好放在末尾
    • 例如:/[\w@#?-]+/
  • 中括号中不存在多位数
var reg = /[a-c]/;// 就是 有abc中的任意一个字符 便可
console.log(reg.test('aeadfgergdfgd'))//true
console.log(reg.test('234werrfrb')) // true
console.log(reg.test('acaca')) // true
console.log(reg.test('bbbbb')) // true 


// [] 中的字符 ‘-’ 是按照 对应的的阿斯克码值对应的
// var reg = /[c-a]/ ;是不能够的会报错
// var reg = /[C-a]/ ;// ASCII:67(大C)-97(小a) 
var reg = /[c\-a]/ ;// c 或者 ‘-’ 或者 a ;这里的‘-’没有意义了,只是一个‘-’
var reg = /[.]/;// 在 [] 中的点 就表明 点儿自己 
//=>[] 中的:量词元字符 | . 再也不具备特殊含义了;


var  reg = /^[1.2]$/;// 该正则 只能匹配一个字符; 1或.或2
console.log(reg.test('1.2'))//false;
console.log(reg.test('1q2'))//false
console.log(reg.test('1')) // true
console.log(reg.test('2'))// true
复制代码

点的相关练习

var  reg = /^1.2$/;// 该正则 1开头 2结尾 中间有一个任意字符
console.log(reg.test('1.2'))//;true
console.log(reg.test('1q2'))//true
console.log(reg.test('1')) // false
console.log(reg.test('2'))// false
复制代码

转义的相关练习

  • 正则中的转义: 就是把 正则中 有特殊含义的字符 转义字符自己
  • 字符串中的转义: 就是把 字符串中 有特殊含义的字符 转义成字符自己;
var  reg = /^1\.2$/;// 该正则 1开头 2结尾 中间有一个点
console.log(reg.test('1.2'))//;true
console.log(reg.test('1q2'))//false
console.log(reg.test('1')) // false
console.log(reg.test('2'))// false */

// 转义 一个是正则中的转义 一个是字符串中的转义
//正则中的转义 就是把 正则中 有特殊含义的字符 转义字符自己
//字符串中的转义 就是把 字符串中 有特殊含义的字符 转义成字符自己;' " \
复制代码

竖|:或的相关练习

  • 直接x|y会存在很乱的优先级问题,通常咱们写的时候都伴随着小括号进行分组,由于小括号改变处理的优先级 =>小括号:分组
var reg = /18|19/;// 含有 18或者19便可
console.log(reg.test('18'))
console.log(reg.test('19'))
console.log(reg.test('189'))
console.log(reg.test('1819'))
console.log(reg.test('819'))
console.log(reg.test('1918'))
console.log(reg.test('118')) 


var reg = /^18|19/;// 18开头的 或者 含有19的 就是true;
console.log(reg.test('18')) // true
console.log(reg.test('19')) // true
console.log(reg.test('189'))//true
console.log(reg.test('1819'))//true
console.log(reg.test('819'))//true
console.log(reg.test('1918'))//true
console.log(reg.test('118')) // false
console.log(reg.test('119')) // true 


var reg = /^18|19$/;// 18开头的 或者 以19结尾的 就是true;
console.log(reg.test('18')) // true
console.log(reg.test('19')) // true
console.log(reg.test('189'))//true
console.log(reg.test('1819'))//true
console.log(reg.test('819'))//true
console.log(reg.test('1918'))//false
console.log(reg.test('118')) // false
console.log(reg.test('119')) // true


// 编写一个正则 只有18 或者 19 匹配的结果是 true; 其余都是false;
var reg = /^(18|19)$/;// 只能匹配18或者19
console.log(reg.test('18')) // true
console.log(reg.test('19')) // true
console.log(reg.test('189'))//false
console.log(reg.test('1819'))//false
console.log(reg.test('819'))//false
console.log(reg.test('1918'))//false
console.log(reg.test('118')) // false
console.log(reg.test('119')) // false


var reg = /^[18|19]$/;// 只能匹配 1 8 | 1 9 五个中的一位 
var reg = /^1[89]$/; // 以1开头 后边是 8或者9 结尾;
var reg = /^[18]9$/; // 以1或者8开头 9结尾
var reg = /^1(8|9)$/;// 以1开头 后边是 8或者9 结尾;
复制代码

四、应用练习

-1)、编写一个正则 能够匹配用户输入的手机号是否合法(宽泛)

规则:

  • 一、以1开头
  • 二、11位数字
  • 三、第二位不能012
let rex = /^1[3-9]\d{9}$/
复制代码

-2)、编写一个正则 能够匹配有效数字

规则:

  • 一、可能出现 + - 号,也可能不出现 : [+-]?
  • 二、一位0-9均可以,多位首位不能是0 :(\d|([1-9]\d+))
  • 三、小数部分可能有可能没有,一旦有后面必须有小数点+数字: (.\d+)?
let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
复制代码

-3)、编写一个正则 能够验证真实姓名的

规则:

  • 一、汉字 : /^[\u4E00-\u9FA5]$/
  • 二、名字长度 2~10位
  • 三、可能有译名 ·汉字 : (·[\u4E00-\u9FA5]{2,10}){0,2}
let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/;
复制代码

-4)、编写一个正则 能够匹配 18-65 之间的年龄

规则:

  • 一、整数
  • 18-19 ;20-59 : [2-5]\d ; 6[0-5]
let reg = /^(1[89]|[2-5]\d|6[0-5])$/;
复制代码

-5)、编写一个正则 能够匹配邮箱

规则一:邮箱的名字由“数字、字母、下划线、-、.”几部分组成,可是-/.不能连续出现也不能做为开始

  • 一、开头是数字字母下划线(1到多位)

  • 二、还能够是 -数字字母下划线 或者 .数字字母下划线,总体零到屡次

    => \w+((-\w+)|(.\w+))*

规则二:

  • 一、@后面紧跟着:数字、字母 (1-多位)

    => @[A-Za-z0-9]+

  • 二、对@后面名字的补充

    • 多域名 .com.cn
    • 企业邮箱 xxx@xxxxxxxx-xxx-office.com

    => ((.|-)[A-Za-z0-9]+)*

  • 三、匹配最后的域名(.com/.cn/.org/.edu/.net...)

    => .[A-Za-z0-9]+

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

-6)、编写一个正则 能够匹配身份证号码

规则:

  • 一、一共18位
  • 二、最后一位多是X
  • 三、身份证前六位:省市县(第一位不能是0)
  • 四、出生的年 19 或 20 :((19|20)\d{2})
  • 五、月份 01-12 :(0[1-9]|1[0-2])
  • 六、日期 01-31 :(0[1-9]|[1-2]\d|3[01])
  • 七、最后一位 => X或者数字 :(\d|X)
  • 八、倒数第二位 => 偶数 女 奇数 男 :(\d{2}(\d))
let reg = /^[1-9]\d{5}((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[01])\d{3}(\d|X)$/i;
复制代码

-7)、编写一个正则 能够匹配用户输入的密码是否符合规则;

规则:

  • 一、8-18位
  • 二、既有大写字母 又有小写字母 还得有数字
function judge(str) {
    if (str.length < 8 || str.length > 18) return false
    if (!/[A-Z]/.test(str)) return false
    if (!/[a-z]/.test(str)) return false
    if (!/\d/.test(str)) return false
    return true;
  }

let reg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,18}$/

//=> 必须有特殊字符时
let reg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[#?&*-])[a-zA-Z0-9#?&*-]{8,18}$/

//=> 密码是由8-18位的数字或者字母组成 不要求全部类型都存在
let reg = /^[0-9A-Za-z]{8,18}$/;
复制代码

另外分享一个正则查找工具:菜鸟工具

3、正则的捕获(exec)

编写一个正则(制定了一套规则):去把某个字符串中符合这个规则的字符获取到

一、语法

  • 正则.exec(字符串)

二、前提

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

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /^\d+$/;
console.log(reg.test(str)); //=>false
console.log(reg.exec(str)); //=>null
复制代码

三、返回值

  • 找到了匹配的文本, 则返回一个数组
    • 数组中第一项:本次捕获到的内容
    • 其他项:对应小分组本次单独捕获的内容
    • index:当前捕获内容在字符串中的起始索引
    • input:原始字符串
    • ......
  • 找不到则不然返回null
let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.log(reg.exec(str));
复制代码

四、捕获的特色

-1)、懒惰性

每执行一次exec,只能捕获到一个符合正则规则的,默认状况下,咱们执行一百遍,获取的结果永远都是第一个匹配到的,其他的捕获不到

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
复制代码

懒惰性的解决办法

想解决懒惰性,咱们首先要知道正则为啥会有这个特性呢?

  • 那咱们先看下咱们写的正则在控制台输出都有啥内容
let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.dir(reg);
复制代码

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.log(reg.lastIndex); //=>0 下面匹配捕获是从STR索引零的位置开始找
console.log(reg.exec(str));
console.log(reg.lastIndex); //=>0 第一次匹配捕获完成,lastIndex没有改变,因此下一次exec依然是从字符串最开始找,找到的永远是第一个匹配到的
复制代码

reg.lastIndex:当前正则下一次匹配的起始索引位置(那咱们就能够知道正则懒惰的缘由了)

  • 懒惰性捕获的缘由:默认状况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,因此找到的永远只是第一个

如今咱们知道了正则为啥会这么“懒”了,咱们就能够“对症下药”治一治他的懒惰性了😄

解决办法:全局修饰符g

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/g;
console.log(reg.exec(str)); //=>["2019"...]
console.log(reg.lastIndex); //=> 13 //=>设置全局匹配修饰符g后,第一次匹配完,lastIndex会本身修改
console.log(reg.exec(str)); //=>["2020"...]
console.log(reg.lastIndex); //=> 26
console.log(reg.exec(str)); //=>["2021"...]
console.log(reg.lastIndex); //=> 39
console.log(reg.exec(str)); //=>null 当所有捕获后,再次捕获的结果是null,可是lastIndex又回归了初始值零,再次捕获又从第一个开始了... 
console.log(reg.lastIndex); //=>0
console.log(reg.exec(str)); //=>["2019"...]
复制代码

上面咱们说过实现正则捕获的前提是:当前正则要和字符串匹配,若是不匹配捕获的结果是null

  • 那咱们验证一下:正则和字符串匹配会不会影响lastIndex
let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/g;
if (reg.test(str)) {
    //=>验证一下:只有正则和字符串匹配咱们在捕获
    console.log(reg.lastIndex); //=>11 基于TEST匹配验证后,LASTINDEX已经被修改成第一次匹配后的结果,因此下一次捕获再也不从头开始了
    console.log(reg.exec(str)); //=>["2020"...]
 }
复制代码

需求练习:编写一个方法execAll,执行一次能够把全部匹配的结果捕获到(前提正则必定要设置全局修饰符g)

~ function () {
    function execAll(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.length === 0 ? null : ary;
    }
    RegExp.prototype.execAll = execAll;
}();

let reg = /\d+/g;
console.log(reg.execAll("金色2019@2020小芝麻")); //=> ["2019", "2020"]
//=>字符串中的MATCH方法,能够在执行一次的状况下,捕获到全部匹配的数据(前提:正则也得设置G才能够)
console.log("金色2019@2020小芝麻".match(reg));//=> ["2019", "2020"]
复制代码

-2)、贪婪性

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

let str = "金色2019@2020小芝麻";
//=>正则捕获的贪婪性:默认状况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
let reg = /\d+/g;
console.log(reg.exec(str)); //=>["2019",......]
复制代码

若是咱们如今的需求是只想要一个“2”

贪婪性的解决办法

在量词元字符后面设置:取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)

let str = "金色2019@2020小芝麻";
reg = /\d+?/g;
console.log(reg.exec(str)); //=>["2",......]
复制代码

思惟导图:正则匹配和捕获

4、正则的其余经常使用知识点

一、问号?在正则中的五大做用:

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

  • 问号左边是非量词元字符:自己表明量词元字符,出现零到一次
  • 问号左边是量词元字符:取消捕获时候的贪婪性
  • (?:) 只匹配不捕获
  • (?=) 正向预查(必须得包含什么)
  • (?!) 负向预查(必须不能有什么)

二、分组()的三大做用

-1)、小分组的第一个做用:提升优先级

需求:捕获身份证号码中的出生年月日及性别

//=>第一项:大正则匹配的结果
//=>其他项:每个小分组单独匹配捕获的结果
//=>若是设置了分组(改变优先级),可是捕获的时候不须要单独捕获,能够基于?:来处理
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <input type="text"/>
  <button>提交</button>
  <h5></h5>
</body>
</html>
<script> /* 点击提交按钮 h5标签展现 这个出生日期和性别 */ let inp = document.querySelector('input'), btn = document.querySelector('button'), h5 = document.querySelector('h5'); btn.onclick = function(){ let val = inp.value; var reg = /^[1-9]\d{5}((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[01])\d{2}(\d)(\d|X)$/i; let ary = reg.exec(val); console.log(ary); if(ary){ // 输入的是一个合法正则 let str = `这我的的出生日期是${ary[1]}${ary[3]}${ary[4]}日;性别是${ary[5]%2 ? '男' : '女'}`; h5.innerHTML = str; }else{ alert('不是一个合法的身份证号码') } } </script>
复制代码

-2)、小分组的第二个做用:分组捕获

需求:既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到 {0} 还须要单独获取0

//=>既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到 {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"]
复制代码

-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
复制代码

三、正则捕获的其余方法及案例

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

  • RegExp.$&:是获取当前大正则的内容
  • RegExp.$1~RegExp.$9:获取当前本次正则匹配后,第一个到第九个分组的信息
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:获取当前本次正则匹配后,第一个到第九个分组的信息
复制代码

-2)、分组具名化(ES6新增)

至关于给分组起名字

  • 语法: ?<名字>
  • 后期匹配完,能够基于匹配结果中的 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); 
复制代码

这里咱们不在讲解,推荐一篇阮一峰老师的ECMAScript 6 入门 里面有详细的讲解,小芝麻就不在这里班门弄斧了😄

-3)、字符串中和正则搭配的捕获方法之—— match

咱们上面已经简单的提过了,这里主要说下matchesec的区别

matchesec的区别

  • 一、设置全局修饰符 g 的状况下:
    • exec 每次执行只能捕获一个匹配的结果
      • 当前结果中包含大正则和小分组匹配的结果
      • 若是想要捕获全,须要执行屡次
    • match 执行一次就能把全部正则匹配的信息捕获到
      • 只有大正则匹配的,并不包含小分组匹配的信息
  • 二、若是不设置 g 的状况下:
    • 都只能捕获到第一个匹配的结果,获取的结果一摸同样 (大正则,小分组都包含)

-4)、字符串中和正则搭配的捕获方法之—— replace

自己是字符串替换的意思

  • 在不使用正则的状况下,每一次执行 replace 只能替换一个,并且不少需求不使用正则是没法解决的
let str = "xiaozhima@2019|xiaozhima@2020";
//=>把"xiaozhima"替换成"小芝麻"
//1.不用正则,执行一次只能替换一个
str = str.replace("xiaozhima","小芝麻").replace("xiaozhima","小芝麻");
console.log(str);

//2.使用正则会简单一点
str = str.replace(/xiaozhima/g,"小芝麻");
console.log(str);
复制代码
  • 把"jinse"替换为"jinsexiaozhima"
let str = "jinse@2019|jinse@2020";
//=>把"jinse"替换为"jinsexiaozhima"
str=str.replace("jinse","jinsexiaozhima").replace("jinse","jinsexiaozhima");
//"jinsexiaozhimaxiaozhima@2019|jinse@2020" 每一次替换都是从字符串第一个位置开始找的(相似于正则捕获的懒惰性)
复制代码

let str = "jinse@2019|jinse@2020";
//=>基于正则g能够实现
str = str.replace(/jinse/g,"jinsexiaozhima");
复制代码

结合正则:

  • 语法:str = str.replace(reg,function)
  • 特色:
    • 一、首先会拿 正则 和 字符串 去进行匹配捕获,匹配捕获一次,就会把函数执行一次
    • 二、而且会把每一次捕获的结果(和esec捕获的结果同样)传递给函数
      • 因此能够用剩余运算符接收每一次正则匹配的结果
      • 结果的顺序:[大正则匹配的、小分组匹配的、捕获的起始索引、原始字符串......]
    • 三、函数中返回啥,就至关于把原始字符串中,大正则匹配的结果替换成啥

案例:把时间字符串进行处理

//=> 要求传入实参格式任意:xx-xx xx:xx ;但索引对应为: 0年 1月 2日 3时 4分 5秒
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 = "2020-4-8 16:36:8";
time = time.formatTime('{0}年{1}月{2}日');
console.log(time); //=> 2020年04月08日
复制代码

案例:单词首字母大写

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!"
复制代码

案例:处理URL参数

// 获取URL中的传参信息(可能也包含HASH值)
String.prototype.queryURLParams = function queryURLParams() {
	let obj = {};
	// 哈希值值的处理
	this.replace(/#([^?=#&]+)/g, (_, group) => obj['HASH'] = group);
	// 问号传参信息的处理
	this.replace(/([^?#=&]+)=([^?#=&]+)/g, (_, group1, group2) => {
		obj[group1] = group2;
	});
	return obj;
};
let str = 'http://www.xxxxxxxxx.cn/?lx=1&from=weixin&name=xxx#video';
let obj = str.queryURLParams();
console.log(obj); //=> {HASH: "video", lx: "1", from: "weixin", name: "xxx"}
复制代码

案例:实现千分符处理

String.prototype.millimeter = function millimeter() {
	return this.replace(/\d{1,3}(?=(\d{3})+$)/g, value => {
		return value + ',';
	});
};

let str = "2312345638";
str = str.millimeter();
console.log(str); //=>"2,312,345,638"
复制代码

思惟导图——正则其余经常使用知识点

相关文章
相关标签/搜索