javascript正则表达式 - 常用的正则表达式总结及正则的捕获

488 阅读4分钟

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战

常用的正则表达式

  • 验证是否为有效数字
  • 规则分析
  1. 可能出现 + - ,也可能不出现
  2. 一位0-9都可以,多位首位不能为0
  3. 小数部分可能有可能没有,一旦有后面必须有小数点加数字
let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
  • 验证密码
  1. 数字、字母、下划线
  2. 6 - 16位
let reg = /^\w{6, 16}$/;
  • 验证真实姓名
  1. 汉字 /^[\u4E00-\u9FA5]$/
  2. 长度 2~10 位
  3. 可能有译名 ·汉字
let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/
  • 验证邮箱
let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
  • 身份证号码
  1. 共18位
  2. 最后一位可能是X
  3. 身份证号前六位:省市县
  4. 中间8位:出生年月日
  5. 最后一位:X或数字
  6. 倒数第二位:偶数:女,奇数:男
  7. 其余的是经过算法算出来的

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

let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/

正则的捕获

  • 实现正则捕获的方法
  • 正则RegExp.prototype上的方法
    • exec
    • test
  • 字符串String.prototype上支持正则表达式的处理方法
    • replace
    • match
    • splite
let str = "Alvin2019yangfan2020qihang2021";
let reg = /\d+/
  • 基于exec实现正则的捕获
  • 捕获到的结果是null或一个数组
    • 第一项是本次捕获的内容
    • 其余项:对应小分组本次单独捕获的内容(小括号中匹配的内容)
    • index:当前捕获内容在字符串中的起始索引
    • input:原始字符串
  • 每执行一次exec只能捕获到一个符合正则规则的,但是默认情况下,不管执行多少遍,获取的结果都是第一个匹配到的,其余的捕获不到
  • 正则捕获的懒惰性

正则的懒惰性:默认值捕获第一个,懒惰性的原因是:默认情况下lastIndex值不会被改变,每次都是从字符串开始位置查找。

  • 可以通过修饰符g(全局匹配)来修饰正则,这样lastIndex值就会自动改变
  • 当全部捕获完成后lastIndex值又会变为0
  • 正则有个lastIndex属性reg.lastIndex,代表当前正则下一次匹配的起始索引位置(默认为0)
  • 在第一次匹配捕获完成后,lastIndex并没有改变,所以下一次exec依然是从字符串的开始位置查找,所以找到的永远都是第一个匹配的
/*
*  需求:由于exec每次只能捕获一次,需要编写一个execAll,执行一次可以把所有匹配的结果都捕获到(前提是正则一定要设置全局修饰符g)
*  字符串中的match方法可以在执行一次,捕获到所有匹配的数据(前提是也需要设置全局修饰符g)
*/
~ function(){
	function execAll(str = ""){
		//要先验证当前正则是否设置了全局修饰符g,否则永远捕获第一个会导致死循环
		if(!this.global) return this.exec(str);
		
		//str 要匹配的字符串
		//this:RegExp的实例(当前正则)
		let ary = [],//存储最终所有捕获的内容
			res = this.exec(str);//每次捕获的内容
		while(res){
			ary.push(res[0]);
			res = this.exec(str);
		}
		return ary;
	}
	RegExp.prototype.execAll = execAll;
}();
let reg = /\d+/g
console.log(reg.execAll(str));
  • 正则的分组捕获
//以身份证号为例:
let str = "130828199001061235"
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));
  • 得到的结果第一项:大正则匹配的结果 其余项:每个小分组单独匹配捕获的结果 如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于:?:来处理(只匹配不捕获) reg = /^(\d{6})(\d{4}(\d{2})(\d{2})\d{2}(\d)(?:\d|X))$/;
  • 不设置g值匹配一次,exec和match获取的结果一样(既有大正则匹配的信息,也有小分组匹配的信息) 但是如果设置了全局修饰符g,即在多次匹配的情况下,match只能把大正则匹配的内容获取到,小分组的信息无法获取到,需要多次执行exec获取 str = "{0}年{1}月{2]日"; reg = /{\d+}/
  • 分组的第三个作用:“分组引用”
  • 分组引用:就是通过“\数字”让其代表和对应分组出现一模一样的内容 str = "book";//good、look、moon... reg = /^【 a-zA-Z ]([a-zA-Z])\1[a-zA-Z]$/; // \1与前面出现的内容一致
  • 正则捕获的贪婪性
  • 正则捕获的贪婪性:默认情况下,正则捕获的时候,是按照当前正则所匹配的最长的结果来获取的 比如:/\d+/g这个正则表示匹配1到多个数字,就是说1个可以,2个可以多个也可以,但是当我们去匹配这样“abc2020de”一个字符串时,会发现第一次匹配会把2020全都匹配到,而不是先匹配一个2再匹配一个0...,这就是正则匹配的贪婪性。
  • 在量词元字符后面设置?,则会取消捕获时候的贪婪性(安装正则匹配的最短结果来匹配)
  • 问号在正则中的五大作用
    • 问号左边是非量词元字符:本身调拨量词元字符,出现零到一次
    • 问号左边是量词元字符:取消捕获时候的贪婪性
    • (?:)只匹配不捕获
    • (?=) 正向预查
    • (?!) 负向预查
  • 其它正则捕获的方法
  • test本身是用来正则匹配的,但是也能捕获
  • RegExp.1 RegExp1~RegExp9:获取当前本次正则匹配后,第一个到第九个分组的信息
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str));//true
cosole.log(RegExp.$1);//0
  • replace字符串中实现替换的方法(一般是伴随正则一起使用的)
  1. 把字符串中所有的Alvin替换成成Hello
  2. 因为字符串的replace方法每次只能替换一个,所以这里就需要调用2次,如果是替换多个的话 就需要调用多次很麻烦
  3. 这里我们就可以通过正则来配合使用实现一次全部替换
let str = "Alvin@2019|Alvin@2020";
let reg = /Alvin/g
str.replace(reg, "Hello");
  • 关于replace配合正则的案例:处理时间字符串

方案一

let str = "2019-08-13";//变为2019年08月13日
let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
//方案一
let time = str.replace(reg, "$1年$2月$3日");
console.log(time);
  • 方案二:[str].replace([reg],[function])
  1. 首先用reg和time进行匹配捕获,能匹配到几次就会把传递的函数执行几次,而且是匹配一次就执行
  2. 不仅把方法执行,而且replace还给方法传递了实参信息(和exec捕获的内容一致的信息:大正则匹配的内容和小分组匹配的内容)
  3. 函数中返回的是啥就把匹配的内容替换成啥
time = str.replace(reg, (all, $1,$2,$3)=>{
	console.log($1,$2,$3);
	return $1 + "年" + $2 + "月" + $3 + "日"
});
  • 单词首字母大写
let str = "good good study, day day up!";
let reg = /\b([a-zA-Z])[a-zA-z]*\b/g; // \b表示单词边界
str = str.replace(reg, (...arg)=>{
	let [word, $1] = arg;
	$1 = $1.toUpperCase();
	word = word.substring(1);
	return $1 + word;
})
console.log(str);