正则表达式浅析

介绍

正则表达式在编程中得到广泛的使用,我们可以很方便的通过正则表达式筛选匹配出我们所需要的内容,进而对这些内容进行修改和替换。相比于静态文本匹配,使用正则表达式能带来更多的灵活性,适用的场景也更多。

JS引擎中处理正则使用的是NFA自动机,其特点是执行慢,但是编译快,适合JS这种动态解释型语言,使用过程中要注意正则匹配过程中的回溯,容易造成性能问题。

1
2
reg: /te{1,3}st/g
string: teest

首先,正则的第一个字符,会与字符串的第一个字符比对,匹配后指针后移到第二个字符e,匹配后,继续后移遇到{1,3}操作符,因为正则匹配是贪婪模式,这时字符串指针会继续后移,遇到第二个e,指针继续后移,发现s和正则e不匹,这时发生回溯,字符串和正则指针回到前一个状态,接着正则指针指向下一个字符s,字符串指针指向下一个字符s,匹配成功,然后继续后移,t也匹配成功,最终完成整个正则匹配过程,匹配结果为teest。从上面可以看出,回溯等于是把之前的操作推倒重来,在设计正则规则的时候需要尽量减少发生回溯的可能。


用法

我们使用正则的时候先定义匹配规则,生成匹配规则有两种形式,分别是字面量和构造函数的方式,然后还可以加上正则的flag值,分别是g表示全局搜索,i表示忽略大小写,m表示多行搜索

1
2
const reg = /abc/gi
const reg1 = new RegExp('abc''gi')

正则中还使用了一些特殊字符,常用的有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
\  转义字符
^ 输入的开始
$ 输入的结束
* 0次或多次
+ 1次或多次
? 0次或1次,跟在量词*、+等后面表示非贪婪模式
. 除换行符外的任意字符
x|y x或y
{n} n次
{n,} n次以上
{n,m} n次到m次之间
(x) 子字符串,结果将会被存储起来,可捕获到,匹配时\1,\2等表示,替换时则是 $1,$2
[xyz] 字符xyz的集合
[^xyz] 非字符xyz
y(?=x) 后面是x的y,不捕获括号中的字符
y(?!x) 后面不是x的y,不捕获括号中的字符
(?<=x)y 前面是x的y,不捕获括号中的字符
(?<!x)y 前面不是x的y,不捕获括号中的字符
\d 表示数字
\D 表示非数字,大写表示[^\d],以下同理
\w 表示字母、数字或者下划线
\s 表示空白字符
\b 表示单词边界的位置,单词边界一般指\w所定义的字符所组成的子串

其中 ^,$,(?=x),(?!x),(?<=x),(?<!x),\b,\B只匹配位置,而不是字符

与此相关的正则表达式方法有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
exec
// const reg = /t(e+)st/g
// const result = reg.exec('teeesteeaxcz')
//["teeest", "eee", index: 0, input: "teeesteeaxcz", groups: undefined]
//exec函数返回的是完整的匹配信息,匹配成功会返回一个数组,数组由匹配字符串以及子字符串构成,即括号中匹配的内容,除此之外还会有,index表示匹配成功的起始索引信息,input表示输入的字符串,匹配失败返回null
test
// const reg = /t(e+)st/g
// const result = reg.test('teeesteeaxcz')
// exec函数返回判断性信息,匹配成功返回true
search
// const str = 'teeesteeaxcz'
// const result = str.search(/t(e+)st/g)
// search函数返回匹配成功的位置索引信息
match
// const str = 'teeesteeaxcz'
// const result = str.match(/t(e+)st/g)
// match函数返回匹配成功的字符串的数组
replace
//const re = /(\w+)\s(\w+)/;
//const str = "charlie james";
//str.replace(re, "$2, $1"); //james charlie
// replace函数返回匹配成功并替换后的新字符串,其中可以使用$n作为括号匹配的变量,如果第二个传入的是函数,那么该函数会被注入多个参数,分别是(match,$1,$2...,index,input),match表示匹配字符串,$n表示括号匹配数,index表示匹配成功的起始索引,input表示输入,函数的返回值则是替换后的字符串

示例

将数字表示成千位分隔

1
2
3
const reg = /(?<!\.\d+)\B(?=(?:\d{3})+\b)/g //123456789->123,456,789,12345.6789->12,345.6789
// 该正则规则的意思是,在需要插入的非单词边界位置,前面没有.和任意数字,即小数点后面的不作千分位划分,在该位置后面需要有三个数字方能匹配。
// 1|2|3|4|5|6|7|8|9 1|2|3|4|5.6|7|8|9 横杠|的位置即是\B匹配的位置