lxmoe的正则表达式学习笔记(二)

132 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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)/,只有在ab可以被匹配到

先行否定断言

先行否定断言:/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

其中xy表示一个范围,可以为{x}{x,}{x,y}分别代表x次,x到无穷次与xy次,而*等价于`{0,}