常用正则表达式及其懒惰性原理
由两部分组成
-
元字符
-
量词元字符
* 0到多个
+ 1到多个
? 0到1个
{n} 出现n次
{n,} 出现到多次
{n,m} 出现n到m次
- 特殊元字符
\ 转义字符(普通>特殊>普通)
. 除\n(换行符)以外任意字符
^ 以哪一个元字符作为开始
$ 以哪一个元字符作为结束
\n 换行符
\d 0~9之间一个数字
\D 非0~9之间任意字符
\w 数字、字母、下划线中的任意一个字符
\s 一个空白字符(包含空格、制表符、换页符)
\t 一个制表符(TAB键:四个空格)
x|y x或者y中的一个字符
[xyz] x或y或z中的一个字符
[^xy] 除了x/y以外的任意字符
[a-z] 指定a-z范围中的任意字符
[^a-z] 除了a-z范围中的任意字符
() 正则中的分组符号
(?:) 只匹配不捕获
(?=) 正向预查
(?!) 反向预查
//普通元字符:代表本身含义的
/xyz/ 此正则匹配的就是"xyz"
// ^ $
let reg = /^\d/; //必须以数字开始
reg.test("lele"); //false
reg.test("lele666"); //false
reg.test("666lele"); //true
let reg = /\d$/; //必须以数字结束
reg.test("lele"); //false
reg.test("lele666"); //true
reg.test("666lele"); //false
let reg = /\d+/; // ^ $都不加:字符串中包含符合内容规则即可
let reg = /^\d+$/; // ^ $都加:字符串只能是和规则内容一致
reg=/^1\d{10}$/
// \ 转义字符 把特殊符号转换为普通符号
let reg = /^\d$/;
reg.test("\\d"); //false
reg = /^\\d$/;
reg.test("\\d"); //true
// x|y ()分组改变优先级,不包起来太乱了
let reg = /^(18|19)$/;
// [] 1.中括号中出现的字符一般都代表本身的含义;2.\d在中括号中代表本身含义;3.中括号中不存在多位数;
let reg = /^[@+]+$/;
- 修饰符
//正则表达式常用修饰符:img
i:ignoreCase 忽略大小写匹配
m:multiline 可以进行多行匹配
g:global 全局匹配
- 常用的正则表达式
/*
1.验证是否为有效数字
规则分析:
1.可能出现+ -号,也可能不出现
2.一位0-9都可以,多位首位不能是0
3.小数不分可能有可能没有,一旦有后面必须有小数点+数字
*/
let reg = /^[+-]?\d|([1-9]\d+)(\.\d+)?$/;
/*
2.验证密码
*/
let reg = /^\w{6,16}$/;
/*
3.验证真实姓名
规则分析:
1.汉字 [\u4E00-\u9FA5]
2.名字长度 2~10
3.可能有译名·汉字
*/
let reg = /^[\u4E00-\u9FA5]{2,10}(.[\u4E00-\u9FA5]){2,10}{0,2}$/;
/*
4.验证邮箱
规则分析:
\w+((-\w+)|(\.\w+))*
1.开头是数字字母下划线1到多位;
2.还可以是“-数字字母下划线”或者“.数字字母下划线”,整体0到多位;
邮箱的名字是由“数字、字母、下划线、-、.”组成的,但是-或.不能连续出现,也不能作为开始。
@[A-Za-z0-9]+
1.@后紧跟数字字母1到多位。
((\.|-)[A-Za-z0-9]+)*
1.对@后面名字的补充
多域名 .com.cn
企业邮箱 xxx@xxx.com
\.[A-Za-z0-9]+
1.这个匹配的是最后的域名(.com/.cn./.net/.edu......)
*/
let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
/*
5.验证身份证号码
规则分析:
1.18位
2.最后一位可能是X
身份证前六位是省市县 \d{6}
中间8位是
年 (1|2)\d{3}或(\d{4})
月 \d[0-2]或(\d{2})
日 \d[1-9]或(\d{2})
最后4位 \d{3}或(\d{2})
最后一位 X或 数字 (\d|X)
倒数第二位 偶数女 奇数男 (\d)
*/
let reg = /^\d{6}(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|X)$/;
- 正则两种创建方式的区别
//1.字面量方式;
//2.构造函数方式;
let reg = /\d+/g;
//构造函数因为传递的是字符串,字符串中的\也有特殊意义。所以需要写\\才代表斜杠
let reg = new RegExp("\\d+","g");
//正则表达式中的部分内容是变量存储的;
//1.两个斜杠中包起来的都是元字符(如果正则中要包含某个变量值,则不能用字面量方式创建)。只能用构造函数方式,因为只有构造函数方式才能进行字符串拼接;
let type = "lele";
reg = /^@"+type +"@$/; //错误
reg = new RegExp("^@"+type+"@$");
- 正则的捕获
实现正则捕获的方法:
1. 正则RegExp.prototype上的方法
exec:
test:
2.字符串String.prototype上支持正则表达式处理的方法
match:
replace:
splite: - 基于exec实现正则捕获
1.捕获的结果是null或者一个数组
第一项:本次捕获到的内容
其余项:对应小分组本次单独捕获的内容
index:当前捕获内容在字符串中的起始索引
input:原始字符串
2.每执行一次exec,只能捕获到一个符合正则规则的,默认情况下,执行多少遍获取的结果都是第一个匹配到的,其余的捕获不到。
**正则捕获懒惰性原因:**默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远是第一个。
解决方案:全局修饰符g。
注意:加了全局修饰符g后,基于test匹配验证后,lastIndex的值已经被修改为第一次匹配后的结果,所以下一次捕获不再从头开始了 - 正则捕获懒惰性原理:
/*
let str = "lele2020lele2021lele2022";
let reg = /\d+/;
reg.exec(str);
//["2020", index: 4, input: "lele2020lele2021"]
//实现正则捕获的前提是:当前正则要和字符串匹配,如果不匹配捕获的是null
let str = "lele2020lele2021lele2022";
let reg = /^\d+$/;
reg.test(str); //false
//===========================================
let str = "lele2020lele2021lele2022";
let reg = /\d+/;
console.log(reg.lastIndex) //0
//第一次捕获完成lastIndex没有改变,所以下一次exec还是从字符串开始位置开始查找,找到的永远第一个匹配到的。任何正则捕获的方法,都是这个机制。手动修改lastIndex不会改变正则中lastIndex的值。
let reg = /\d+/g;
console.log(reg.lastIndex) //11 设置全局匹配修饰符g后,第一次匹配完lastIndex会自己修改
console.log(reg.lastIndex) 0
reg.exec(str) ["2020"]
console.log(reg.lastIndex) 8
reg.exec(str) ["2021"]
console.log(reg.lastIndex) 16
reg.exec(str) ["2022"]
//当全部捕获后,再次捕获,再次捕获的结果是null,d但是lastIndex又回归了初始值0,再次捕获又从第一个开始
console.log(reg.lastIndex) 24
reg.exec(str) null
console.log(reg.lastIndex) 0
reg.exec(str) ["2020"]
*/
自定义execAll方法,执行一次可以把所有匹配的结果捕获到(前提是设置了全局修饰符g)
~ function(){
function execAll(str = ""){
//进来之后先判断当前正则是否设置了g,不设置则不能进行循环捕获,否则会导致死循环
//str:要匹配的字符串
//this:RegExp的实例(当前操作的正则)
//arr 存储最后所有捕获的信息,res存储每次捕获的内容
if(!this.global) return this.exec(str);
let arr = [];
res = this.exec(str)
while(res){
//将每次捕获内容存到arr
arr.push(res[0]);
//只要捕获的内容不为null,则继续捕获下去
res = this.exec(str);
}
return arr.length === 0 ? null : arr;
}
RegExp.prototypr.execAll = execAll;
}();
let reg = /\d+/g;
console.log(reg.execAll(str)); //["2020","2021","2022"]
字符串中的match方法,可以在执行一次的情况下,捕获到所有匹配的数据等同于execAll方法,(前提是设置了全局修饰符g)。