1. 修饰符
g
:global 全文搜索,如果不添加,则搜索到第一个匹配时停止i
:ignoreCase 忽略大小写,默认大小写敏感m
:multiline 多行匹配
2. 元字符
正则表达式由两种基本字符类型组成:
- 原义文本字符
- 元字符
元字符是在正则表达式中有特殊含义的非字母字符,包含:
\
:转义,将具有特殊意义的元字符转成原义文本字符.
:除了换行以外的所有字符+
:至少一个,一次或者多次?
:至多一次,零或者一次*
:任意次$
:以 … 结尾^
:字符类取反、或者以 … 开头|
:或()
:分组{}
:用来包裹量词范围[]
:用来包裹字符类 | 字符 | 含义 | | —- | —- | | \t | 水平制表符 | | \v | 垂直制表符 | | \n | 换行符 | | \r | 回车符 | | \0 | 空字符 | | \f | 换页符 | | \cX | 与X对应的控制字符(Ctrl+X) |
3. 字符类
一般情况下,正则表达式一个字符对应一个字符,如 ab\t
,表示字符 ‘ab’ 以及一个制表符 tab
如果我们需要匹配一类字符,可以使用元字符 []
来构建一个简单的类。所谓的类是指符合某些特性的对象,是一个泛指。如 [abc]
把字符 a 或 b 或 c 归为一类,只要有里面的一个,就能匹配。
'a1b2c3c'.replace(/[abc]/g, 'X'); // 'X1X2X3X'
中括号中出现的元字符一般都是代表本身含义的
let reg = /^[.]+$/;
reg.test('.'); //=> true
中括号中的 -
有特殊含义,一般需要放在后面或者前面来代表本义
中括号中出现两位数,不是两位数,而是代表两个数中的任意一个
let reg = /^[12-65]$/g //=> 表示 1 或者 2-6 或者 5
3.1 字符类取反
使用元字符 ^
创建反向类/负向类,就是不属于某类的内容。如 [^abc]
表示不是字符 a 或 b 或 c 的内容。
'a1b2c3c'.replace(/[^abc]/g, 'X'); // 'aXbXcXc'
3.2 范围类
使用 -
来连接两个字符,如 [a-z]
表示从 a 到 z 的任意字符,这是一个闭区间,包含 a 和 z 本身。
'a1b2d3x4z9'.replace(/[a-z]/g, 'Q'); // 'Q1Q2Q3Q4Q9'
在 []
组成的类内部是可以连写的,如 [a-zA-Z]
注意:横线并不是元字符,但是在上面的情况是特指范围,不会匹配到 -
。如果需要匹配到横线,只需要在后面再加上横线。[a-z-]
表示 a 到 z 以及横线。
3.3 预定义类
正则表达式提供预定义类来匹配常见的字符类。
字符 | 等价类 | 含义 |
---|---|---|
. | [^\r\n] | 除了回车符和换行符之外的所有字符 |
\d | [0-9] | 数字字符 |
\D | [^0-9] | 非数字字符 |
\s | [\t\n\x0B\f\r] | 空白字符 |
\S | [^\t\n\x0B\f\r] | 非空白字符 |
\w | [a-zA-Z_0-9] | 单词字符(字母、数字、下划线) |
\W | [^a-zA-Z_0-9] | 非单词字符 |
4. 边界
正则表达式还提供了几个常用的边界匹配字符
^
:以……开始$
:以……结束\b
:单词边界\B
:非单词边界
// 开头结尾匹配
'@12@12@1'.replace(/@./g, '0'); // '02020'
'@12@12@1'.replace(/^@./g, '0'); // '02@12@1'
'@12@12@1'.replace(/@.$/g, '0'); // '@12@120'
// 多行开头结尾匹配
‘@12
@12
@12’.replace(/^@./g, '0');
// '02
// @12
// @12'
‘@12
@12
@12’.replace(/^@./gm, '0');
// '02
// 02
// 02'
// 单词边界
'This is a boy'.replace(/is/g, '0'); // 'Th0 0 a boy'
'This is a boy'.replace(/\bis\b/g, '0'); // 'This 0 a boy'
'This is a boy'.replace(/\Bis\b/g, '0'); // 'Th0 is a boy'
5. 量词
?
:出现零次或者一次(最多一次)+
:出现一次或多次(至少出现一次)*
:出现零次或者多次(任意次){n}
:出现 n 次{n,m}
:出现 n 到 m 次{n,}
:至少出现 n 次
注意:量词只作用于紧挨它的前一个正则字符
贪婪模式:正则表达式会在范围允许内尽可能多的匹配。
非贪婪模式:让正则表达式尽可能少的匹配,一旦匹配成功就不再继续匹配。
默认正则表达式都是贪婪模式。如果需要实现非贪婪模式,只需要在量词后加上 ?
即可。
// 贪婪模式
'123456789'.replace(/\d{3,6}/g, 'X'); // 'X78'
// 非贪婪模式
'123456789'.replace(/\d{3,6}?/g, 'X'); // 'XX78'
6. 分组
如果要匹配 destiny 连续出现的场景,如果使用 destiny{3}
,那么只会匹配到 destinyyy
,而不是 destinydestinydestiny
。
这时就需要使用 ()
分组,使量词作用于分组。(destiny){3}
分组的作用:
- 提升优先级
- 分组匹配,可以理解成大正则里边的小正则
- 分组捕获
let reg = /^1|8$/
'1' //=> true
'8' //=> true
'18' //=> true
//=> 以 18 开头或 19 结束
let reg = /^18|19$/;
'18'; //=> true
'19'; //=> true
'1819'; //=> true
'181'; //=> true
'819'; //=> true
'189'; //=> true
'119'; //=> true
//=> 如果只是想要匹配 18 或 19
let reg = /^(18|19)$/
6.1 或
使用 |
可以达到或的效果
'ByronCasper'.replace(/Byron|Casper/g, 'X'); // 'XX'
'ByronsperByrCasper'.replace(/Byr(on|Ca)sper/g, 'X'); // 'XX
6.2 分组捕获
分组后,可以使用 $1 - $n
来表示各个分组匹配到的内容。即可以把分组内的内容捕获到。
'2018-05-11'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$2/$3/$1'); //=> 05/11/2018
6.3 分组引用
正则中,使用 \1
、\2
等,来引用正则中出现的分组捕获的内容
//=> 匹配到四个字符的字母,其中第一个与最后一个一样,第二位与倒数第二位一样
let reg = /^([a-Z])([a-Z])\2\1¥/;
'oppo' //=> true
'abba' //=> true
6.4 忽略分组
如果不希望捕获某些分组,只需要在分组内加上 ?:
就可以,如 (?:Byron).(ok)
,这时,$1
就捕获 ok 分组匹配的内容
7. 前瞻
正则表达式从文本头部向尾部开始解析,称为“前”。
前瞻就是在正则表达式匹配到规则中的时候,向前检查是否符合断言,后顾方向相反。JavaScript 不支持后顾。
符合和不符合特定断言称为肯定/正向匹配和否定/负向匹配
名称 | 正则 |
---|---|
正向前瞻 | exp(?=assert) |
负向前瞻 | exp(?!assert) |
正向前瞻:例 \w(?=\d)
,在是单词的基础上向前判断后面紧跟的是否是数字,这里只匹配单词,后面括号内的只是判断单词是否符合条件。
'a2*3'.replace(/\w(?=\d)/g, 'X'); // 'X2*3'
'a2*34v8'.replace(/\w(?=\d)/g, 'X'); // 'X2*X4X8'
负向前瞻:例 \w(?!\d)
,在单词的基础上向前判断后面紧跟的是否不是数字,这里也是只匹配单词,后面的只是判断条件。
'a2*3'.replace(/\w(?!\d)/g, 'X'); // 'aX*3'
'a2*34v8'.replace(/\w(?!\d)/g, 'X'); // 'aX*3XvX'