持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 2 天,点击查看活动详情
正则表达式强悍无比,在不同的语言中会有些许差异,本文主要总结在 Javascript 中的正则表达式;
javascript 中的正则表达式在 ECMAScript 3 开始提出,并在后面的规范中得到增强;
你可以通过下面的文章来阅读正则表达式的历史:
1、概述
-
正则表达式是用于匹配字符串中字符组合的 模式,由普通字符 和 特殊字符(元字符)组成;
-
普通字符:包括没有显示指定为元字符的所有可打印和不可打印字符;(eg:大写字母、小写字母、数字、标点符号)
-
特殊字符(元字符):元字符是正则表达式中的关键字(eg:^、$、*、+、?、.、()、[]、{}、\、|),其具有特殊的含义,如果要把元字符当作普通字符,需要使用转义字符( \ )转义。
-
-
在 JavaScript 中,有正则表达式对象(RegExp);
-
正则表达式在 Javascript 中用于正则表达式对象(RegExp) 的
exec()
和test()
方法,和 字符串对象(String)的match()
、matchAll()
、replace()
、search()
、split()
等方法;
2、创建一个正则表达式
1、使用正则表达式字面量
const reg = /ab+c/;
const reg = /a/; // 只匹配出现的第一个 a;
const reg = /a/g; // 匹配全部的a
复制代码
正则表达式字面量每一次被使用时都会转换成一个正则对象;
2、使用RegExp
构造函数创建一个正则表达式对象
const reg = new RegExp('a',g);
const reg = new RegExp(/[A-Z]/,i);
复制代码
3、正则表达式的基本语法
修饰符、字符匹配、量词、位置匹配、分支、分组;
1、正则字面量使用//
包围
const reg = /daxia/;
复制代码
2、标志、修饰符
在正则表达式字面量中,标志位放在 //
的后面;
- g:全局搜索
- i:不区分大小写
- m:多行匹配,使边界字符
^
和$
匹配每一行的开头和结尾; - s:使正则表达式中的字符圆点
.
中包含换行符\n
; - u:使用 unicode 码的模式进行匹配;
- y:执行"粘性"搜索,匹配从目标字符串的当前索引为 lastIndex 的位置开始匹配,匹配失败返回 null;
eg:
// 不区分大小写,并全局匹配 a
const reg = /a/gi;
'abcABC'.match(reg); // ['a', 'A']
复制代码
3、字符
-
.:匹配除换行符(
\n
、\r
)之外的所有单字符; -
[]:定义匹配的字符范围;在
[]
里的 *,+,?,. 等表示的是字符 -
\d:匹配数字 [0-9];
-
\D:匹配非数字 [^0-9];
-
\w:匹配 [0-9a-zA-Z_];
-
\W:匹配 [^0-9a-zA-Z_];
-
\s:匹配一个空白字符;
-
\S:匹配一个非空白字符;
-
匹配所有字符:[\s\S] 或 [\d\D] 或 [\w\W]
- \u2028:行分隔符
- \u2029:段分隔符
eg:
// 匹配任意字符
const reg = /[\s\S]/;
'danid2348*$@R%'.match(reg); // ['d', index: 0, input: 'danid2348*$@R%', groups: undefined]
// 全局匹配任意字符
const reg1 = /[\s\S]/g;
'danid2348*$@R%'.match(reg1); // ['d', 'a', 'n', 'i', 'd', '2', '3', '4', '8', '*', '$', '@', 'R', '%']
复制代码
4、量词
- *:匹配前面一个表达式0次或多次
- +:匹配其前面一个表达式1次或多次;
- ?:匹配前面一个表达式0次或1次,加在 * 和 + 后面可以实现非贪婪匹配;
- {n}:匹配前面一个表达式 n 次;
- {n,}:匹配前面一个表达式至少 n 次;
- {n,m}:匹配前面一个表达式 n 到 m 次;
在量词后面加?
就可以实现惰性匹配(eg:+?表示只匹配一次);
eg:
const reg = /\d+/g;
// 全局匹配连续的数字串
'124ddd123'.match(reg); // ['124', '123']
复制代码
5、分支
使用管道|
操作符来实现分支;
eg:
const reg = /you|boy/g;
// 全局匹配 you 或 boy
'hello, you are a boy'.match(reg); // ['you', 'boy']
复制代码
注:
-
分支结构是惰性的,匹配到了分支左边的就不会匹配分支右边的;
const reg = /roo|root/g; 'root'.match(reg) // ['roo'] 复制代码
6、分组
一个()
里面的内容是一个分组,指定匹配括号里的内容,一个圆括号是一个捕获组,javascript 会在正则对象中存储每一个捕获组匹配到的内容,并且可以在正则表达式中通过 \number
的形式调用;
1、使用构造函数的全局属性获取分组
const str = '123 456';
const reg = /(\d+) (\d+)/g;
// 使用分组匹配
reg.exec(str);
// ['123 456', '123', '456', index: 0, input: '123 456', groups: undefined]
RegExp.$1;
// 123
RegExp.$2;
// 234
复制代码
2、在正则表达式内应用分组
const str = "! 456 ! i am daxia";
const reg = /(\!+)[\d\D]+\1/;
// reg 中 \1 代表前面(\!+)匹配到的内容
console.log(reg.exec(str));
// ['! 456 !', '!', index: 0, input: '! 456 ! i am daxia', groups: undefined]
复制代码
3、如果只想使用括号的功能,而不希望括号称为为捕获组,使用非捕获括号 (?:p)
的形式就好了
'ab'.match(/(ab)/); // ['ab', 'ab', index: 0, input: 'ab', groups: undefined]
'ab'.match(/(?:ab)/); // ['ab', index: 0, input: 'ab', groups: undefined]
复制代码
4、其他内容
-
括号嵌套时,按树形结构解析分组;
const reg = /((da)(xia))/; reg.exec('daxia is a daxia'); // ['daxia', 'daxia', 'da', 'xia', index: 0, input: 'daxia is a daxia', groups: undefined] 复制代码
-
\10 表示匹配第 10 个分组;
const reg = /(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)\10/; reg.exec('1234567891010'); // ['1234567891010', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', index: 0, input: '1234567891010', groups: undefined] 复制代码
-
使用不存在的分组(分组只到 \3,但是在正则表达式中使用了 \4,匹配的是 \4 对应的字符);
const reg = /(a)(b)(c)\1\2\3\4/; reg.exec('abcabc abcabc4'); // null 复制代码
-
分组后面有量词,那么全局 RegExp 中存储的是最后一次分组匹配的数据;
const reg = /(\d)+/; reg.exec('123 456'); // ['123', '3', index: 0, input: '123 456', groups: undefined] RegExp.$1; // '3' 复制代码
7、位置匹配词
-
^:匹配开始,如果在 [] 中使用则表示不匹配方括号里的内容;
let re = /^a/; const str = 'bcda'; // null const str = 'abcda'; // 可以匹配到 复制代码
-
$:匹配结尾
-
\b: 匹配一个单词边界,即 \W 与 \w 之间的位置和 \w 与 ^、$ 之间的位置。
-
\B:匹配一个非单词边界;即 \w 与 \w之间,\W 和 \W 之间,\W 与 ^ 、$ 之间。
-
exp1(?=exp2):查找 exp2 前面的 exp1
'<h1>daxia</h1>'.match(/<(?=\/)/); // [ // '<', // 使用非捕获元素时,括号里的内容不会存在捕获组里 // index: 9, // input: '<h1>daxia</h1>', // groups: undefined // ] 复制代码
-
(?<=exp2)exp1:查找 exp2 后面的 exp1
'<h1>daxia</h1>'.match(/(?<=daxia)</); // [ // '<', // 使用非捕获元素时,括号里的内容不会存在捕获组里 // index: 9, // input: '<h1>daxia</h1>', // groups: undefined // ] 复制代码
-
exp1(?!exp2):查找后面不是 exp2 的 exp1
-
(?<!exp2)exp1:查找前面不是 exp2 的 exp1;
8、操作符优先级
操作符描述 | 操作符 | 优先级 |
---|---|---|
转义符 | \ | 1 |
括号和方括号 | (…)、(?:…)、(?=…)、(?!…)、[…] | 2 |
量词限定符 | {m}、{m,n}、{m,}、?、*、+ | 3 |
位置和序列 | ^、$、\元字符、一般字符 | 4 |
管道符(竖杠) | | | 5 |
注:
- 使用连续的量词时注意要使用括号;