正则表达式
1. 什么是正则表达式?
-
正则表达式是由一个字符序列形成的搜索模式。
-
当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。
-
正则表达式可以是一个简单的字符,或一个更复杂的模式。
-
正则表达式可用于所有文本搜索和文本替换的操作。
2. 正则表达式的创建
2.1 字面量
// 在一对反斜线中写正则表达式内容,如/abc/
// 正则表达式里面不需要加引号 不管是数字型还是字符串型
var reg = /正则表达式/修饰符;
var reg = /hello/g;
2.2 构造函数
//构造正则表达式的实例,如new RexExp('abc')
//内部传入的参数为字符串/字符串的变量
var reg =new RegExp("正则表达式","修饰符")
var reg =new RegExp("hello","g");
3. 字符分类
3.1 普通字符
字母、数字、下划线、汉字、没有特殊含义的符号(,;!@等)
3.2 特殊字符
\:将特殊字符转义成普通字符
3.3 模式修饰符
- i:ignoreCase,匹配时忽视大小写
- m:multiline,多行匹配
- g:global,全局匹配
字面量创建正则时,模式修饰符写在一对反斜线后
4. 正则表达式实例方法
4.1 exec
匹配到返回值是一个result数组:[匹配的内容,index: 在str中匹配的起始位置,input: 参数字符串,groups: undefined] 否则返回null
var str = 'hello123 world hello javascript';
// 字面量
// 如果没有设置一个全局模式 每次都会回到索引0的位置重新查找
var reg = /hello/g;
// exec匹配成功返回一个数组 失败则会返回null
console.log(reg.lastIndex); //0
console.log(reg.exec(str)); //[ 'hello',index: 0,input: 'hello123 world hello javascript',groups: undefined ]
console.log(reg.exec(str)); //[ 'hello',index: 15,input: 'hello123 world hello javascript',groups: undefined ]
console.log(reg.lastIndex); //20
// 利用循环查看每次exec校验之后的结果
while (true){
var result = reg.exec(str);
// 何时终止这个循环
if(!result){
break;
}
console.log(result[0],result['index']); //hello 0 hello 15
}
注意点:
- 如果正则表达式中有修饰符"g",这时,在正则表达式的实例reg中会维护lastIndex属性,记录下一次开始的位置,当第二次执行exec的时候,从lastIndex开始检索。
- 如果正则表达式中没有修饰符"g",不会维护lastIndex属性,每次执行从开始位置检索
4.2 test
用来测试待检测的字符串中是否有可以匹配到正则表达式的字符串,如果有返回true,否则返回false
// test匹配成功 返回true 失败返回false
var str = 'hello123 world hello javascript';
var reg = /hello/g;
console.log(reg.test(str)); //true
注意点:
- 如果正则表达式中有修饰符"g",这时,在reg中会维护lastIndex属性,记录下一次开始的位置,当第二次执行test的时候,从lastIndex开始检索。
- 如果正则表达式中没有修饰符"g",不会维护lastIndex属性,每次执行从开始位置检索
4.3 toString/toLocaleString
// toString toLocaleString 返回 /hello/ 字符串
var str = 'hello123 world hello javascript';
var reg = /hello/g;
console.log(reg.toString(str)); // /hello/g
console.log(reg.toLocaleString(str)); // /hello/g
4.4 valueOf
// 返回正则表达式本身
var str = 'hello123 world hello javascript';
var reg = /hello/g;
console.log(reg.valueOf()); // /hello/g
5 正则表达式实例属性
5.1 lastIndex
当没设置全局匹配时,该属性值始终为0。每次正则查找的起点就是lastIndex。
// lastIndex 如果没有开启全局匹配模式 始终为0 每次校验都会从开始位置重新校验
// 如果开启了全局模式 每次校验都会记录当前满足条件的字符的位置 下次校验从这个位置开始
var str = 'hello hello hello';
var reg1 = /hello/;
var reg2 = /hello/g;
// 没有开启全局模式的
console.log(reg1.lastIndex); //0
console.log(reg1.exec(str)); //[ 'hello',index: 0,input: 'hello hello hello',groups: undefined ]
console.log(reg1.lastIndex); //0
// 开启全局模式的
var str = 'hello hello hello';
var reg1 = /hello/;
var reg2 = /hello/g;
console.log(reg2.lastIndex); //0
console.log(reg2.exec(str)); //返回第一个hello
console.log(reg2.lastIndex); //0
console.log(reg2.lastIndex); //0
console.log(reg2.exec(str)); //返回第一个hello
console.log(reg2.lastIndex); //5
console.log(reg2.lastIndex); //5
console.log(reg2.exec(str)); //返回第二个hello
console.log(reg2.lastIndex); //11
console.log(reg2.lastIndex); //11
console.log(reg2.exec(str)); //返回第三个hello
console.log(reg2.lastIndex); //17
console.log(reg2.lastIndex); //返回null
console.log(reg2.exec(str)); //0
console.log(reg2.lastIndex); //返回第一个hello
5.2 ignoreCase、global、multiline
判断正则表达式中是否有忽略大小写、全局匹配、多行匹配三个模式修饰符
// ignoreCase、global、multiline
var reg3 = /hello/igm;
console.log(reg3.ignoreCase); //true
console.log(reg3.global); //true
console.log(reg3.multiline); //true
5.3 source
返回字面量形式的正则表达式
// source 类似于toString
var reg4 = /hello/igm;
// console.log(reg4.source); //hello
6. 正则表达式语法-元字符
6.1 直接量字符
字符 | 匹配 |
---|---|
字母和数字字符 | 自身 |
\o | Null字符 |
\t | 制表符 |
\n | 换行符 |
\v | 垂直制表符 |
\f | 换页符 |
\r | 回车符 |
//直接量字符
var str = 'hello \nworld hello javascript';
var reg = /\n/;
console.log(reg.test(str)); //true
console.log(reg.exec(str)); //[ '\n',index: 6,input: 'hello \nworld hello javascript',groups: undefined ]
6.2 字符集合
- [abc] 查找方括号之间的任何字符
- [0-9] 查找任何从0至9的数字
- [^xyz] 一个反义或补充字符集,也叫反义字符组。也就是说,它匹配任意不在括号内的字符。你也可以通过使用连字符 ‘-’ 指定一个范围内的字符。反义字符要和方括号一起使用。
var str = 'asd qwe zxc rty';
// 匹配的是一个整体 abc
var reg = /asd/;
// 使用字符集合 只要有其中的一个字符 就会满足校验条件
var reg2 = /[awe]/;
// console.log(reg2.exec(str)); //[ 'a', index: 0, input: 'asd qwe zxc rty', groups: undefined ]
// 做一个区间的值的选择 [0-9] [a-z] [A-Z]
var str = 'asd1 qwe2 zxc3 rty';
var reg1 = /[0-9]/;
var reg2 = /[a-z]/;
var reg3 = /[A-Z]/;
console.log(reg1.exec(str)); //[ '1', index: 3, input: 'asd1 qwe2 zxc3 rty', groups: undefined ]
console.log(reg2.exec(str)); //[ 'a', index: 0, input: 'asd1 qwe2 zxc3 rty', groups: undefined ]
console.log(reg3.exec(str)); //null
// [^] [^0-9] 除了0-9之间的数字其他字符都可以
// [a-z]
// [A-Z]
var str = 'asd1 qwe2 zxc3 rty';
var reg = /[^asd]/;
console.log(reg.exec(str)); //[ '1', index: 3, input: 'asd1 qwe2 zxc3 rty', groups: undefined ]
// \d -> [0-9]
注意:^写在[]里面是补充字符集
var str = 'abc qwe abd1,2'
console.log(str);
var reg1 = /[^abc ]/igm;
console.log(reg1.exec(str)); //true
7. 边界符
^ 匹配输入开始;
$ 匹配输入结尾。
^和 $ 在一起,表示必须是精确匹配。
// ^ 以什么开头 以谁结束
// 写在方括号内 代表取反
// var reg = /[^0-9]/;
// 写在方括号外 以谁结束
var reg = /^[0-9]/;
// console.log(reg.test('qweqwe'));
// $ 以什么开头 以谁结束
var reg2 = /[a-z]$/
// console.log(reg2.test('qweqwe'));
// ^ $一起使用 精确匹配
var reg3 = /^abc$/;
// console.log(reg3.test('abc qwe abc')); //false
// console.log(reg3.test('abc')); //true
var reg4 = /^[abc]$/;
console.log(reg4.test('a'));
\b 匹配一个零宽单词边界(zero-width word boundary),表示一个单词(而非字符)边界,也就是单词和空格之间的位置,或者字符(\w)与字符串开头或者结尾之间的位置。
\B 匹配一个零宽非单词边界(zero-width non-word boundary),与"\b"相反。
var str = 'Hello World Hello JavaScript';
var reg1 = /\bHello\b/g;
var reg2 = /\BScrip\B/g;
console.log(reg1.exec(str));
console.log(reg2.exec(str));
8. 字符类
字符类 | 含义 |
---|---|
. | 匹配除换行符\n和回车符之外的任何单个字符,等效于**[^\n\r]** |
\d | 匹配一个数字字符,等效于[0-9] |
\D | [^0-9] |
\w | 匹配包括下划线的任何单个字符,包括AZ,az,0~9和下划线**""**,等效于[a-zA-Z0-9] |
\W | [^a-zA-Z0-9_] |
\s | 匹配任何Unicode空白字符,包括空格、制表符、换页符等,等效于[\f\t\n\r] |
\S | [^\f\t\n\r] |
“.” 除换行符\n和回车符之外的任何单个字符
\d 匹配一个数字字符,等效于[0-9]
\D 等效于**[^0-9]**
\w匹配包括下划线的任何单个字符,包括AZ,az,0~9和下划线**""**,等效于[a-zA-Z0-9]
\W [^a-zA-Z0-9_]
\s 匹配任何Unicode空白字符,包括空格、制表符、换页符等,等效于[\f\t\n\r]
\S 等效于**[^\f\t\n\r]**
// . 除了\n和\r之外 全部都可以匹配
var reg = /./;
console.log(reg.exec('\nasd123'));
var str = 'hello world hello javascript';
// \d -> [0-9]
var reg = /^\d/;
console.log(reg.test(str));
// \D -> [^0-9]
var reg2 = /^\D/;
console.log(reg2.test(str));
var str = 'hello world hello javascript';
// \w -> [a-zA-Z0-9_]
var reg = /^\w/;
console.log(reg.test(str));
// \W -> [^a-zA-Z0-9_]
var reg2 = /^\W/;
console.log(reg2.test(str));
// 以空白字符开头
var str = '\nHello World Hello 123JavaScript';
var reg1 = /^\s/g;
console.log(reg1.exec(str));
// 不以空白字符开头
var str = 'Hello World Hello 123JavaScript';
var reg1 = /^\S/g;
console.log(reg1.exec(str));
9. 数量词
字符 | 含义 |
---|---|
* | >=0次 |
+ | ≥1 次 |
? | 0或1次 |
{n} | n 次 |
{n,} | ≥n 次 |
{n,m} | n到m 次 |
X* 匹配前面的模式 x -> 0 或多次。等价于{0,}
X+ 匹配前面的模式 x -> 1 或多次。等价于 {1,}。
X? 匹配前面的模式 x -> 0 或 1 次。等价于{0,1}
X{n} n为非负整数。前面的模式 x 重复出现 n 次时匹配
X{n,} n为非负整数。前面的模式 x 重复出现至少 n 次时匹配。
X{n,m} n和m为非负整数。前面的模式 x 重复出现至少 n 次,至多 m 次时匹配。
// * 允许出现0次或一次
var reg = /^a*$/;
console.log(reg.test('aaa'));
// +允许一次或多次
var reg2 = /^a+$/;
console.log(reg2.test('aaaaaa'));
// ?允许0次或多次
var reg2 = /^a?$/;
console.log(reg2.test('a'));
// {n} 固定重复n次
var reg = /^a{3}$/;
// var reg = /^\d{3}$/; = var reg = /^a{3}$/;
// 只要满足字符是0-9之间的字符 就可以连续编写为16 不需要重复
console.log(reg.test('aaa'));
// {n,}大于等于n次
var reg2 = /\d{3,}/;
console.log(reg2.test('012'));
// {n,m}大于等于n次 小于等于m次
var reg3 = /^\d{3,6}$/;
console.log(reg3.test('012012012012'));
10. 案例
- 匹配QQ号
- 匹配身份证号
- 匹配11位有效手机号码
// 1.不能以数字0开始,只能由数字组成,长度为5-11位
var regQQ = /^[1-9]\d{4,10}$/;
console.log(regQQ.test('123123123')); //true
// 2.不能以数字0开头,只能由数字组成,最后一位可能是x,X,数字
var regID = /^[1-9]\d{16}[xX\d]$/;
console.log(regID.test('123123123123123323')); //true
// 3.以1为开头 第二位为3,4,5,7,8中的任意一位 最后以0-9的9个整数结尾
var regPhone = /^1[3,4,5,7,8]\d{9}$/;
console.log(regPhone.test('18822473596')); //true
11. 重复方式
11.1 贪婪模式
尽可能多的匹配(首先取最多可匹配的数量为一组进行匹配),当匹配剩余的字符串,还会继续尝试新的匹配,直到匹配不到为止,为默认模式。
// 对字符串"123456789",匹配其中的数字3-6次:\d{3,6},先匹配数字出现6次的字符串(123456),然后再从剩余字符串(789)中匹配出现数字3次的情况,剩余字符若没有出现数字3次则停止匹配.
var str = "123456789";
var reg = /\d{3,6}/g;
console.log(reg.exec(str)); //[ '123456', index: 0, input: '12345678', groups: undefined ]
console.log(reg.exec(str)); // [ '789', index: 6, input: '123456789', groups: undefined ]
console.log(reg.exec(str)); // null
11.2 非贪婪模式
尽可能少的匹配(每次取最少匹配的数量为一组进行匹配),直到匹配不到为止,使用方法:在量词后加上 ?
// 对字符串"123456789",匹配其中的数字3-6次:\d{3,6},先匹配数字出现3次的字符串(123),然后再从剩余字符串(456789)中匹配出现数字3次的情况,剩余字符若没有出现数字3次则停止匹配.
var str = "123456789";
var reg = /\d{3,6}?/g;
console.log(reg.exec(str)); //[ '123', index: 0, input: '123456789', groups: undefined ]
console.log(reg.exec(str)); // [ '456', index: 3, input: '123456789', groups: undefined ]
console.log(reg.exec(str)); // [ '789', index: 6, input: '123456789', groups: undefined ]
12. 选择、分组、引用
12.1 选择
字符"|"用于分隔供选择的字符,选择项的尝试匹配次序是从左到右,知道发现了匹配项,如果左边的选择项匹配,就忽略右边的匹配项,即使它可以产生更好的匹配。
// | 选择 类似于 或 a || b || c
//选择项的尝试匹配次序是从左到右,知道发现了匹配项,
// 如果左边的选择项匹配,就忽略右边的匹配项
var str = 'qqqwwwjscsshtmlcss';
var reg = /html|css|js/;
console.log(reg.exec(str)); //[ 'js', index: 6, input: 'qqqwwwjscsshtmlcss', groups: undefined ]
12.2 分组
// 分组
// var str = 'qqqwwwcsshtmlcss';
var str = 'i like css';
var reg = /i like html|css|js/;
console.log(reg.exec(str)); //[ 'css', index: 7, input: 'i like css', groups: undefined ]
12.3 捕获
// 捕获
var reg = /(\d{4})-(\d{2})-(\d{2})/
var date = '2021-08-29'
reg.test(date)
// 捕获之前要先test/exec
console.log(RegExp.$1); //2021
console.log(RegExp.$2); //08
console.log(RegExp.$3); //29
12.4 引用
// 引用
// is 前后一样才会返回true 否则返回false
var reg = /(\w{3}) is \1/;
console.log(reg.test('kid is kid')); //true
console.log(reg.test('aaa is aaa')); //true
13 String对正则表达式的支持
13.1 search
查找字符串中是否有匹配正则的字符串,有则返回字符串第一次出现时的位置,无则返回null。是否有全局匹配都不会影响返回结果。
// 引用
// is 前后一样才会返回true 否则返回false
var reg = /(\w{3}) is \1/;
console.log(reg.test('kid is kid')); //true
console.log(reg.test('aaa is aaa')); //true
13.2 match
匹配字符串中符合正则表达式的字符串,并返回该字符串的一个数组,其中包括字符串内容、位置
如果正则设置全局匹配,则一次性返回所有符合正则表达式的字符串数组
如果其中添加了分组,返回符合要求的字符串以及分组的一个数组,但如果同时开启全局匹配则不会在数组中添加分组内容
/match
var str = 'hello world hello hello';
var reg1 = /hello/;
var reg2 = /hello/g;
var reg3 = /(he)llo/;
var reg4 = /(he)llo/g;
// 如果正则表达式没有开启全局匹配 那么match的用法和exec基本一样
console.log(str.match(reg1)); //[ 'hello',index: 0,input: 'hello world hello hello',groups: undefined ]
// 开启全局匹配 match会将所有匹配到的字符串放到一个数组内 返回给我们
console.log(str.match(reg2)); //[ 'hello', 'hello', 'hello' ]
// 添加了分组 返回符合要求的字符串以及分组的一个数组 类似exec
console.log(str.match(reg3)); //[ 'hello','he', index: 0,input: 'hello world hello hello',groups: undefined ]
// 如果同时开启全局匹配则不会在数组中添加分组内容
console.log(str.match(reg4)); //[ 'hello', 'hello', 'hello' ]
13.3 split
//split 以某种形式分割字符串
var str = 'larray123terry456zhangsan789lisi';
var reg = /\d+/;
console.log(str.split(reg)); //[ 'larray', 'terry', 'zhangsan', 'lisi' ]
13.4 replace
//replace \b \B
var str = 'Hello World Hello JavaScript';
var reg = /\bHello\b/g;
console.log(reg.exec(str)); //[ 'Hello',index: 0,input: 'Hello World Hello JavaScript',groups: undefined ]
console.log(str.replace(reg,'Hi')); //Hi World Hi JavaScript
14 前瞻表达式
表达式 | 名称 | 描述 |
---|---|---|
(?=exp) | 正向前瞻 | 匹配后面满足表达式exp的位置 |
(?!exp) | 负向前瞻 | 匹配后面不满足表达式exp的位置 |
var str = 'Hello, Hi, I am Hilary.';
//后面一定要匹配什么
var reg = /H(?=i)/g;
var newStr = str.replace(reg, "T");
console.log(newStr); //Hello, Ti, I am Tilary.