正则,熟悉的陌生人,经常用,却很少总结
一、概念
正则表达式是描述字符模式的对象。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
三种生成方式:
- const reg = eval(‘/hello/i’) - 不推荐
- const reg = /hello/i
- const reg = new RegExp(‘hello’, ‘i’)
正则可视化网站:https://regexper.com/

二、修饰符
修饰符与其他语法特殊,字面量方法声名的时候放到//后,构造函数声明的时候,作为第二个参数传入。整个正则表达式可以理解为正则表达式规则字符串+修饰符。
- g:global 执行一个全局匹配
- s:dotAll模式:可以让点(.)符号匹配任意单个字符
- i:ignore case执行一个不区分大小写的匹配
- u:unicode模式:正确处理大于\uFFFF的Unicode字符
- m: multiple lines多行匹配,仅有换行符的时候生效
- y:sticky模式:确保匹配必须从剩余的第一个未知开始
常用的 igm 就不多做解释了,说说不常见的 umy ~
dotAll模式 - s修饰符
s修饰符,可以让点(.)符号匹配任意单个字符
1 | let se = /foo.bar/ |
sticky模式 - y修饰符
y修饰符的作用与g修饰符类似,不同的地方,g修饰符只要剩余未知中存在匹配就可以;而y修饰符确保匹配必须从剩余的第一个未知开始,这也就是“粘连”的涵义
1 | let str = 'aaa_aa_a' |
unicode模式 - u修饰符
用来正确处理大于\uFFFF的Unicode字符;\uD83D\uDC2A -> 🐪 是一个四个字节的UTF-16编码
1 | /\uD83D/u.test('\uD83D\uDC2A') // false |
扩展:常用汉字的unicode编码范围 \u4E00(一)- \u9FA5(龥) https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php
三、方法和属性
1 | let reg = new RegExp('hello', 'ig'); |
3.1: lastIndex
返回一个整数,表示下一次开始搜索的位置。该属性可读写,但是只在进行连续搜索时有意义(/g 或 /s)
1 | const reg = /a+/g |
- 注意:带有g修饰符时,正则表达式内部会记住上一次的lastIndex属性,这时不应该更换所要匹配的字符串
1
2
3
4
5
6
7// 带有g修饰符时,正则表达式内部会记住上一次的lastIndex属性,这时不应该更换所要匹配的字符串
const r = /aa/g
console.log(r.test('aa')) // true
console.log(r.lastIndex) // 2
console.log(r.test('_aa_')) // false
r.lastIndex = 1 // 将lastIndex手动改成1
console.log(r.test('_aa_')) // true
3.2: STRING与正则相关的方法 match、replace、search、split
- 1 match 返回一个数组,成员是所有匹配的子字符串;匹配失败返回null
1
2
3
4
5
6
7
8
9let str = '_x_x'
console.log(str.match(/x/)) // ['x', index: 1, input: '_x_x']
console.log(str.match(/x/g)) // ['x', 'x']
console.log(str.match(/y/)) // null
// 设置正则表达式的lastIndex属性,对match方法无效
let reg = /x/g
reg.lastIndex = 5
console.log(reg.exec(str)) // null
console.log(str.match(reg)) // ['x', 'x'] - 2 search 返回第一个满足条件的匹配结果在整个字符串中的位置
1
2console.log('_x_x'.search(/x/)) // 1
console.log('_x_x'.search(/y/)) // -1 - 3 split 按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组
1
2
3
4
5
6console.log('a, b,c, d'.split(/, */)) // [ 'a', 'b', 'c', 'd' ]
// 第二个参数是返回数组的最大成员数
console.log('a, b,c, d'.split(/, */, 2)) // [ 'a', 'b' ]
console.log('aaa**a*'.split(/a*/)) // [ '', '*', '*', '*' ]
// 如果正则表达式带有括号,则括号匹配的部分也会作为数组成员返回
console.log('aaa*a*'.split(/(a*)/)) // ["", "aaa", "*", "", "*", "a", "*"] - 4 replace - 可以替换匹配的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20console.log('aaa'.replace(/a/, 'b')) // baa
console.log('aaa'.replace(/a/g, 'b')) // bbb
// 一、replace方法的第二个参数可以使用美元符号$,用来指代所替换的内容
// 1、$&:匹配的子字符串
console.log('abc'.replace(/b/, '$&')) // abc
// 2、$`:匹配结果前面的文本
console.log('abc'.replace(/b/, '$`')) // aac
// 3、$':匹配结果后面的文本
console.log('abc'.replace(/b/, '$\'')) // acc
// 4、$n:匹配成功的第n组内容,n是从1开始的自然数
console.log('abc'.replace(/(b)/, '$1d')) // abdc
// 5、$$:指代美元符号$
console.log('abc'.replace(/b/, '$$')) // a$c
// 二、replace方法的第二个参数还可以是一个函数
const res = '3 and 5'.replace(/[0-9]+/g, (match) => {
return 2 * match
})
console.log(res) // 6 and 10
四、语法
- 原义字符(字面量字符)
- 元字符(点字符.、非打印字符、预定义类、边界)
- 转义符\
- 字符类[]
- 字符类取反[^]
- 范围类[-]
- 选择符|
- 量词
- 贪婪与懒惰(量词后加?)
- 分组()与反向引用(非捕获组 ?:)
- 零宽断言(前瞻(?= 先行断言、?! 先行否定断言) 后顾(?<= 后行断言、?<! 后行否定断言))
4.1 原义字符(字面量字符)
如果某个字符只表示它字面的含义,那么它们就叫做“字面量字符”(literal characters)
1 | /dog/.test('IT dog') // dog为原义字符 |
4.2 元字符
有一部分字符有特殊含义,不代表字面的意思。它们叫做“元字符”(metacharacters)
1 | // 1、点字符(.)- 除了换行(\n)、行结束符(\u2028)、回车(\r)、段分隔符(\u2029)外的其他任意单字符 |
4.3 转义符\
对于那些有特殊含义的字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠。
1 | // 需要转义的,一共12个字符 ^.[$()|*+?{\ |
4.4 字符类 []
表示有一系列字符可供选择,只要匹配其中一个就可以了
1 | console.log(/[abc]/.test('hello')) // false |
4.5 字符类取反[^] - 也叫”脱字符”
表示除了字符类之中的字符,其他字符都可以匹配 - 中括号内第一个为^
1 | console.log(/[^abc]/.test('hello')) // true |
4.6 范围类[-] - 也叫”连字符”
表示一定范围内
1 | console.log(/[0-9]/.test('123')) // true |
4.7 选择符|
表示“或关系”(OR)
1 | console.log(/cat|dog/.test('cat'), /cat|dog/.test('at')) // true false |
4.8 量词 ?*+{m,n},用于限定子模式出现在正则表达式的次数
1 | // 1、匹配n次:{n} |
4.9 贪婪与懒惰(量词后加?)
- 上面的量词符,默认情况下都是最大可能匹配,即匹配到下一个字符不满足匹配规则为止,这被称为贪婪模式
- 要开启懒惰模式,需要在量词后加?
- 贪婪模式量词: {x,y} {x,} ? * +
- 懒惰模式量词: {x,y}? {x,}? ?? *? +?
1
2
3
4
5
6const str = 'baaaac'
console.log(str.match(/ba{1,4}/), str.match(/ba{1,4}?/)) // ['baaaa'] ['ba']
console.log(str.match(/ba{2,}/), str.match(/ba{2,}?/)) // ['baaaa'] ['baa']
console.log(str.match(/ba?/), str.match(/ba??/)) // ['ba'] ['b']
console.log(str.match(/ba*/), str.match(/ba*?/)) // ['baaaa'] ['b']
console.log(str.match(/ba+/), str.match(/ba+?/)) // ['baaaa'] ['ba']
4.10 分组()与反向引用(非捕获组 ?:)
1 | // 一、分组(子表达式)可以理解为,数学运算中的括号,用于计算的分组使用 |
4.11 零宽断言
1 | // 1、前瞻lookahead(?= 先行断言、?! 先行否定断言、负向先行断言) |
五、常用正则举例
1 | // 1、手机号 |