1.认识正则
• (RegExp)Regular Expression:是js的一个内置类
- 正则,就是一个规则,可以检验某个字符串是否符合这个规则(test),也可以把字符串中符合某个规则的字符捕获到(exec 、match…)
- 主要用来处理字符串
let reg = /\d+/; // 0-9之间的数字出现1到多次
let str = 'd12fgh';
console.log(reg.test(str)); // true
console.log(reg.exec(str)); // ["12", index: 1, input: "d12fgh", groups: undefined]
2.正则的组成
• 正则由元字符和修饰符组成
• 正则由元字符和修饰符组成
元字符:量词元字符、特殊元字符、普通元字符
量词元字符:
*: 0到多次
+:1到多次
?: 0到1次
{n}: 出现n次
{n,}: 至少出现n次
{n,m}: 出现n到m次
特殊元字符:
\ : 转义字符,可以把特殊的元字符转换为普通的元字符,也可以把普通元字符转换为特殊元字符
. :任意字符(除了换行符意外)
^:以什么什么开头
$:以什么什么结尾
\n:换行符
\d:0到9之间的任意数字
\D:非0到9之间的任意数字
\w:数字、字母、下划线
\t:制表符
\b:单词边界
\s:空白符
x|y: x和y之间的任意一个
[a-z]:a到z之间的任意一个字符
[a-zA-Z0-9]:a到z或者A到Z或者0到9之间的任意字符
[^a-z]:除了a到z之外的任意一个字符
():分组
(?:):只匹配,不捕获
(?=):正向预查
(?!):负向预查
普通元字符:
b
n
d
...
修饰符:就是对正则起到修饰作用的
i-->ignoreCase:不区分大小写
m-->multiline:多行匹配
g-->global:全局匹配
3.正则的简单使用
-
开头和结尾(^ $)
// let reg = /18$/; // 以18结尾就可以 // console.log(reg.test('189')) // false // console.log(reg.test('198')) // false // console.log(reg.test('218918')) // true // let reg = /^18$/; // 既要以18开头,又要以18结尾 // console.log(reg.test('189')) // false // console.log(reg.test('198')) // false // console.log(reg.test('218918')) // false // console.log(reg.test('18e18')) // false // console.log(reg.test('18')) // true // let reg = /^\d{2}$/; // console.log(reg.test('e2')); // false // console.log(reg.test('2e')); // false // console.log(reg.test('2e2')); // false // console.log(reg.test('e2e')); // false // console.log(reg.test('22')); // true // console.log(reg.test('2')); // false // 如果 ^ $都不加,那只要出现正则里的字符就可以 // 如果^ $都加,那匹配的字符必须跟正则的内容一样才可以 let reg= /^123456$/; console.log(reg.test('000123456')); // true 只要结尾匹配上就可以
- 转义字符()
// let reg = /^2.3$/; // . 是除了\n之外的任意字符 // console.log(reg.test('2.3')) // true // console.log(reg.test('2e3')) // true // console.log(reg.test('2@3')) // true // 基于转义字符,把.转化成普通的元字符 // let reg = /^2\.3$/; // console.log(reg.test('2.3')) // true // console.log(reg.test('2e3')) // false // console.log(reg.test('2@3')) // false // let str = '中\\国'; // 转义字符在字符串里也适用 // console.log(str) // '中\国' // let reg = /^\\d$/; // console.log(reg.test('\\d')) // true
-
x|y : x或者y之间取一个
//let reg = /^18|29$/;
// console.log(reg.test('18')); // true
// console.log(reg.test('29')); // true
// console.log(reg.test('189')); // true
// console.log(reg.test('129')); // true
// console.log(reg.test('1829')); // true
---------------------------------------------------------------------------------------------
直接写 x|y会存在很乱的优先级问题,一般我们写的时候都伴随着小括号进行分组,因为小括号改变处理的优先级 =>小括号:分组
// let reg = /^(18|29)$/;
// console.log(reg.test('18')); // true
// console.log(reg.test('29')); // true
// console.log(reg.test('189')); // false
// console.log(reg.test('129')); // false
// console.log(reg.test('1829')); // false
// ():分组
// 1、提高匹配的优先级
// 2、分组引用
// 3、分组捕获
// 先捕获最大的内容,然后按照分组在依次进行捕获
// let str = 'a3a';
// let reg = /[a-z](\d)([a-z])/;
// console.log(reg.exec(str)) // ['a3a','3',...]
4.匹配重复出现的字符(abab、abbc…)
// let str = 'moon';
// ([a-z])\1:让第一次分组的字符在出现一次
// let reg = /^[a-z]([a-z])\1[a-z]$/;
// console.log(reg.test('moon'));
// console.log(reg.test('mwsn'));
// let str = 'abab';
// let reg = /^([a-z])([a-z])\1\2$/ // 让第一次和第二次分组的字符各自再出现一次
// console.log(reg.test('abab'))
// console.log(reg.test('mnmn'));
// console.log(reg.test('aaaa'))
// console.log(reg.test('moon'))
// let str = 'foood';
// let reg = /^[a-z]([a-z])\1\1[a-z]$/; // 让第一次分组的字符在出现两次
// console.log(reg.test('foood')) // true
// console.log(reg.test('fonod')) // true
5.[]中不允许出现多位数
[]中不允许出现多位数
// let reg = /^[21-68]$/; // 2 或者 1-6 或者8 之间取一个数
// console.log(reg.test('21')); // false
// console.log(reg.test('68')); // false
// console.log(reg.test('2')); // true
// console.log(reg.test('5')); // true
// console.log(reg.test('8')); // true
// let reg = /^[@#ws]$/; // 中括号中的字符出现一次即可
6.正则的正负向预查
/*
正则的正负向预查:
(?=):正向预查
(?!):负向预查
*/
// 正向预查
// let reg = /zhufeng(?=peixun)/; // zhufeng后面必须跟着peixun才能匹配成功
// console.log(reg.test('zhufengpeixunwwwwwww')); // true
// 负向预查:
// let reg = /zhufeng(?!peixun)/;// zhufeng后面必须不跟着peixun才能匹配成功
// console.log(reg.test('zhufengwwwwwww')) // true
// console.log(reg.test('zhufengpeixunwww')) // false
4.正则的创建方式(字面量和构造函数创建方式)
//=>构造函数因为传递的是字符串,\需要写两个才代表斜杠
// let reg = /\d+/g;
// reg = new RegExp("\\d+", "g");
// console.log(reg); // /\d+/
//=>正则表达是中的部分内容是变量存储的值
//1.两个斜杠中间包起来的都是元字符(如果正则中要包含某个变量的值,则不能使用字面量方式创建)
// let type = "zhufeng";
// reg = /^@"+type+"@$/;
// console.log(reg.test("@zhufeng@")); //=>false
// console.log(reg.test('@"typeeeee"@')); //=>true
//2.这种情况只能使用构造函数方式(因为它传递的规则是字符串,只有这样才能进行字符串拼接)
// reg = new RegExp("^@" + type + "@$");
// console.log(reg);
// console.log(reg.test("@zhufeng@"));//=>true
5.正则的捕获
正则的捕获:把正则匹配到的内容捕获到
let str = "asd123";
let reg = /\d{3}/;
let res = reg.exec(str);
console.log(res);// ["123", index: 3, input: "asd123", groups: undefined]
// exec:他是正则实例的一个公有属性,用来捕获符合规则的内容
1、返回值:是一个数组,如果捕获不到就是null
1、第一项是最大的捕获内容
2、数组的后几项是分组捕获的内容
3、index是第一次捕获位置的索引
4、input是原字符串
1.正则捕获的懒惰性
利用正则捕获时只能捕获到第一次出现符合规则的内容,如果想取消正则的懒惰性,就加修饰符g
// 正则身上有一个lastIndex属性,他记录的是正则捕获开始的位置的索引,如果正则不加g,那不管捕获多少次lastIndex始终是0,所以每一次捕获到的都是第一次负责规则的内容(这就是正则的懒惰性)
let str = "asd123as456as789d";
let reg = /\d{3}/;
// console.log(reg.lastIndex); // 0
// console.log(reg.exec(str)); // '123'
// console.log(reg.lastIndex); // 0
// console.log(reg.exec(str)); // '123'
// console.log(reg.lastIndex); // 0
// console.log(reg.exec(str)); // '123'
// 如果正则加上g,那每一次捕获之后正则的lastIndex属性就会记录下一次开始捕获的位置的索引,当下一次再次捕获的时候就会在lastIndex的位置继续捕获(这就是取消正则的懒惰性)
reg = /\d{3}/g;
// console.log(reg.lastIndex) // 0
// console.log(reg.exec(str)) // '123'
// console.log(reg.lastIndex) // 6
// console.log(reg.exec(str)) // '456'
// console.log(reg.lastIndex) // 11
// console.log(reg.exec(str)) // '789'
// console.log(reg.lastIndex) // 16
// console.log(reg.exec(str)) // null
// console.log(reg.lastIndex) // 0
// console.log(reg.exec(str)) // 跟第一次一样了 '123'
2.封装一个捕获全部内容的方法(不包含分组捕获)
let str = "asd123as456as789d";
let reg = /\d{3}/g;
// 正则身上有一个global属性,如果当前正则没有修饰符g,那他的值就是false,反之就是true
function myExec(str){
// 如果正则不加g,那正则的私有属性global的值就是false,
// 如果global的值就是false那就把他捕获一次直接return出去就好了
if(!this.global){
return this.exec(str);
};
let ary = []; // 用来存放每一次捕获到的内容
let res = this.exec(str) // 先捕获第一次
while(res){
// 每捕获一次就往ary里push一次捕获到的内容,直到捕获到null为止
ary.push(res[0])
// 然后在继续捕获
res = this.exec(str) // 继续进行捕获
}
// 如果正则第一次就捕获不到,while就不会执行,那ary是空数组,直接给他return null就好了
return ary.length === 0?null:ary;
};
// RegExp.prototype.myExec = myExec;
// console.log(reg.myExec(str)); // ['123','456','789']
3.字符串的match方法
String.prototype.match()
match是字符串上的一个方法,用来捕获负责符合规则的内容
let str = "asd123as456as789d";
let reg = /\d{3}/g;
console.log(str.match(reg)); // ['123','456','789'] 和咱们刚才封装的方法实现的功能是一样的
// ---------------------------------------------------------------------------------------
// match的其他特点:
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/;
//=>如果正则不设置g只会捕获一次,exec和match获取的结果一致
console.log(reg.exec(str)); // ["{0}", "0", index: 0, input: "{0}年{1}月{2}日", groups: undefined]
console.log(str.match(reg)); // ["{0}", "0", index: 0, input: "{0}年{1}月{2}日", groups: undefined]
//=>如果正则加上g,在多次捕获的情况下match只能把大正则匹配的内容获取到,小分组匹配的信息无法获取
reg = /\{(\d+)\}/;
console.log(str.match(reg)); // ["{0}", "{1}", "{2}"]
4.字符串的matchAll方法
String.prototype.matchAll()
match是字符串上的一个方法,他的返回值是一个迭代器,迭代器里的每一项是每一次捕获到的所有内容(大捕获和分组捕获) 【迭代器可以用for of遍历】
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(str.matchAll(reg)); // RegExpStringIterator {} 迭代器
for (var ss of str.matchAll(reg)) {
console.log(ss);
// ["{0}", "0", index: 0, input: "{0}年{1}月{2}日", groups: undefined]
// ["{1}", "1", index: 4, input: "{0}年{1}月{2}日", groups: undefined]
// ["{2}", "2", index: 8, input: "{0}年{1}月{2}日", groups: undefined]
}
// 去遍历当前的迭代器可以得到每一次捕获的所有内容
5.正则的贪婪性
正则捕获的贪婪性:默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
在量词元字符后面设置?来取消正则的贪婪性
// 正则的贪婪性
let str = '2019';
let reg = /\d+/g;
console.log(str.match(reg)); // ['2019']
//=>在量词元字符后面设置?来取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)
reg = /\d+?/g;
console.log(str.match(reg)); // ["2", "0", "1", "9"]