这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战
常用的正则表达式
- 验证是否为有效数字
- 规则分析
- 可能出现 + - ,也可能不出现
- 一位0-9都可以,多位首位不能为0
- 小数部分可能有可能没有,一旦有后面必须有小数点加数字
let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
- 验证密码
- 数字、字母、下划线
- 6 - 16位
let reg = /^\w{6, 16}$/;
- 验证真实姓名
- 汉字 /^[\u4E00-\u9FA5]$/
- 长度 2~10 位
- 可能有译名 ·汉字
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]+$/
- 身份证号码
- 共18位
- 最后一位可能是X
- 身份证号前六位:省市县
- 中间8位:出生年月日
- 最后一位:X或数字
- 倒数第二位:偶数:女,奇数:男
- 其余的是经过算法算出来的
//小括号的第二个作用:分组捕获,不仅可以把大正则匹配的信息捕获到,还可以单独捕获到每个小分组的内容
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.9:获取当前本次正则匹配后,第一个到第九个分组的信息
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str));//true
cosole.log(RegExp.$1);//0
- replace字符串中实现替换的方法(一般是伴随正则一起使用的)
- 把字符串中所有的Alvin替换成成Hello
- 因为字符串的replace方法每次只能替换一个,所以这里就需要调用2次,如果是替换多个的话 就需要调用多次很麻烦
- 这里我们就可以通过正则来配合使用实现一次全部替换
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])
- 首先用reg和time进行匹配捕获,能匹配到几次就会把传递的函数执行几次,而且是匹配一次就执行
- 不仅把方法执行,而且replace还给方法传递了实参信息(和exec捕获的内容一致的信息:大正则匹配的内容和小分组匹配的内容)
- 函数中返回的是啥就把匹配的内容替换成啥
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);