持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
五种断言
断言指的是对模式的边界匹配,比如在头部开始,或者在尾部开始,又或者指定一个边界开始,基本分为五种断言方式,分别为边界断言,先行断言,先行否定断言,后行断言,后行否定断言。
边界断言
边界断言可以在指定边界进行匹配,常用的元字符为^,$,^可以在头部进行匹配,$可以在尾部进行匹配
let reg = /^a/;
let _reg = /a$/;
let str = "ba";
console.log(reg.test(str)); // false
console.log(_reg.test(str)); // true
"ba"头部为b,所以并没有被/^a/匹配到,而"ba"的尾部为a所以可以被/a$/匹配到。
先行断言
先行断言:/x(?=y)/,在y前面的区域对x进行匹配
let reg = /a(?=b)/;
let str = "ba";
let _str = "ab";
console.log(reg.test(str)); // false
console.log(reg.test(_str)); // true
上面的例子使用先行断言/a(?=b)/,只有在a在b前可以被匹配到
先行否定断言
先行否定断言:/x(?!y)/只有不在y前面的区域才能对x进行匹配,可以用数学集合来解释,先行断言与先行否定断言的并集为全集。
let reg = /a(?!b)/;
let str = "ca";
let _str = "ab";
console.log(reg.test(str)); // true
console.log(reg.test(_str)); // false
上面的例子使用先行否定断言/a(?!b)/,即只有不在b前的区域内可以对a匹配,而ca没有这个区域。
后行断言
后行断言:/(?<=y)x/,与先行断言方向相反,即在y后的区域对x进行匹配
let reg = /(?<=b)a/;
let str = "ba";
let _str = "ab";
console.log(reg.test(str)); // true
console.log(reg.test(_str)); // true
上面例子使用后行断言/(?<=b)a/,只有在b后的区域内可以对a匹配
后行否定断言
后行否定断言:/(?<!y)x/,只有不在y后面的区域才能对x进行匹配,与后行断言的并集为全集
let reg = /(?<!b)a/;
let str = "abc";
let _str = "ba";
console.log(reg.test(str)); // true
console.log(reg.test(_str)); // false
三种方式
正则表达式有三种创建方式,分别为字面量创建,构造函数+字面量创建,构造函数+字符串创建
字面量创建
let reg = /a/;
构造函数+字面量创建
通过RegExp构造函数创建正则,本质上正则表达式是一个对象实例,参数是字面量形式。
let reg = new RegExp(/a/);
构造函数+字符串创建
通过RegExp构造函数创建正则,参数是字符串形式。
let reg = new RegExp("a");
不同之处
会有人想这三种方法就直接使用字面量创建不是最简单的形式么,其实字面量创建和构造函数创建在编译时机有着很大的区别
- 字面量创建的正则会在脚本运行后进行编译
- 构造函数创建的正则会在脚本运行时进行编译
编译时机上的区别让两种形式的使用场景发生了变化
- 脚本运行后编译适用于正则保持不变的情况,这样会使性能更加稳定
- 脚本运行时编译适用于正则需要随着用户的交互发生变化,这样就需要构造函数来创建和脚本实时编译。
多种匹配
简单匹配
简单匹配即想要匹配特定的字符,比如我想要在一串字符串内寻找某个特定的词,可以使用简单模式进行直接匹配,这也是其特点,简单模式直接且严格。
let reg = /abc/;
let str = "abcdf";
let _str = "a bcdf";
console.log(reg.test(_str)); // false
console.log(reg.test(str)); // true
组匹配
组匹配可以搭配()与-元字符使用,可以匹配多组数据,常用来切割时间戳等场景
let reg = /(\d{4})-(\d{2})-(\d{2})/;
let str = "2022-07-08";
console.log(reg.exec(str));
还可以使用具名组匹配可以为匹配结果指定一个名字
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let str = "2022-07-08";
console.log(reg.exec(str));
具名组匹配的结果会被添加到groups属性中,那么我们还可以通过解构赋值来拿到结果
const { groups: { year } } = reg.exec(str);
console.log(year); // 2022
范围匹配
使用[]与=元字符进行范围匹配
let reg = /[0-9]/
let str = "404"
console.log(reg.test(str)) // true
如上匹配0-9区间内的数字,还可以通过范围匹配来匹配所有的汉字,字母等等
多次匹配
使用+,{x,y},*元字符来特定匹配某规则n次
使用+可以匹配多次
let reg = /[0-9]/;
let _reg = /[0-9]+/;
let str = "500a502";
console.log(str.match(reg)); // 5
console.log(str.match(_reg)); // 500
使用{x,y}可以指定次数范围
let reg = /[0-9]{1,2}/;
let str = "500a5";
console.log(str.match(reg)); // 50
其中x和y表示一个范围,可以为{x},{x,}与{x,y}分别代表x次,x到无穷次与x到y次,而*等价于`{0,}