关于正则编写的细节这里不多做赘述,本文主要是列出 exec
、match
、matchAll
、test
这几个函数之间的区别。
详细的正则表达式文档参照 正则表达式 - JavaScript | MDN
exec
函数
-
调用者:正则表达式
-
返回示例
属性 描述 [0]
、[1]
、[2]
...下标 0
对应的是最近一个匹配到的字符串,往后的下标对应捕获的子串(也就是正则表达式里用括号包裹的内容)index
此次匹配到的字符串在原始字符串中的索引值 input
原始字符串 -
当正则表达式携带
g
标志时,exec
函数会从正则表达式变量的lastIndex
(默认为0
)起开始检索原始字符串,一旦匹配成功就会停止继续向后匹配,并会在执行后把正则表达式变量的lastIndex
值置成此次匹配的子串末尾的下标 + 1(如果匹配成功),或置回0
(如果匹配失败)。这就会导致多次执行exec
可能会有不同的结果,像下面这样:let myRe = /d(b+)(c*)d/g; let str = 'cdbbcdbsbzdbd'; myRe.exec(str); // 第 1 次执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] // 上面结果中的 "bb" 就是第一个括号捕获的内容,"c" 就是第二个括号捕获的内容 // 执行完后 myRe.lastIndex 为 6,下一次 exec 将从原始字符串下标 6 开始检索 myRe.exec(str); // 第 2 次执行结果 => ["dbd", "b", "", index: 10, input: "cdbbcdbsbzdbd"] // 上面结果中的 "b" 就是第一个括号捕获的内容,"" 就是第二个括号捕获的内容 // 执行完后 myRe.lastIndex 为 13,下一次 exec 将从原始字符串下标 13 开始检索 myRe.exec(str); // 第 3 次执行 => null // 执行完后 myRe.lastIndex 为 0,下一次 exec 将从原始字符串下标 0 开始检索 myRe.exec(str); // 第 4 次执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] // 执行完后 myRe.lastIndex 为 6
-
不过正如上面所说,
lastIndex
是正则表达式变量的一个属性,如果你没有把正则表达式赋给一个变量,每次用的都是新的正则表达式,那就不存在多次执行导致不同结果的现象了,像下面这样:let str = 'cdbbcdbsbzdbd'; /d(b+)(c*)d/g.exec(str); // 执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] /d(b+)(c*)d/g.exec(str); // 执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] /d(b+)(c*)d/g.exec(str); // 执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"]
-
当正则表达式 不 携带
g
标志时,exec
函数同样一旦匹配成功就会停止继续向后匹配,并且不会改变正则表达式变量的lastIndex
,这样每次调用exec
得到的结果都是相同的,像下面这样:let myRe = /d(b+)(c*)d/; let str = 'cdbbcdbsbzdbd'; myRe.exec(str); // 第 1 次执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] // 执行完后 myRe.lastIndex 为 0,下一次 exec 将从原始字符串下标 0 开始检索 myRe.exec(str); // 第 2 次执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] // 执行完后 myRe.lastIndex 为 0,下一次 exec 将从原始字符串下标 0 开始检索 myRe.exec(str); // 第 3 次执行 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] // 执行完后 myRe.lastIndex 为 0,下一次 exec 将从原始字符串下标 0 开始检索
match
函数
-
调用者:字符串
-
当正则表达式携带
g
标志时,match
函数会以数组形式返回所有匹配的子串(并不会捕获括号中的内容),不会更改正则表达式变量的lastIndex
,像下面这样:let myRe = /d(b+)(c*)d/g; let str = 'cdbbcdbsbzdbd'; str.match(myRe); // 执行结果 => ["dbbcd", "dbd"] // 执行完后 myRe.lastIndex 为 0
-
当正则表达式 不 携带
g
标志时,match
函数的返回形式与exec
函数一致,并且不会改变正则表达式变量的lastIndex
,像下面这样:let myRe = /d(b+)(c*)d/; let str = 'cdbbcdbsbzdbd'; str.match(myRe); // 执行结果 => ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"] // 执行完后 myRe.lastIndex 为 0
matchAll
函数
-
调用者:字符串
-
matchAll
使用的正则表达式必须携带g
标志,matchAll
函数会以迭代器(iterator
)形式返回所有匹配的子串,每个子串都是与exec
函数的返回格式一致,不会更改正则表达式变量的lastIndex
,像下面这样:let myRe = /d(b+)(c*)d/g; let str = 'cdbbcdbsbzdbd'; [...str.matchAll(myRe)]; // 执行结果 => // [ // ["dbbcd", "bb", "c", index: 1, input: "cdbbcdbsbzdbd"], // ["dbd", "b", "", index: 10, input: "cdbbcdbsbzdbd"] // ] // 执行完后 myRe.lastIndex 为 0
test
函数
-
调用者:正则表达式
-
返回布尔值,
true
匹配成功,false
代表匹配失败 -
test
函数与exec
函数在对待lastIndex
上的行为完全一样,在携带g
标志时,从正则表达式变量的lastIndex
(默认为0
)起开始检索原始字符串,一旦匹配成功就会停止继续向后匹配,并会在执行后把正则表达式变量的lastIndex
值置成此次匹配的子串末尾的下标 + 1(如果匹配成功),或置回0
(如果匹配失败);不携带g
标志时,test
函数同样一旦匹配成功就会停止继续向后匹配,并且不会改变正则表达式变量的lastIndex
:let myRe = /d(b+)(c*)d/g; let str = 'cdbbcdbsbzdbd'; myRe.test(str); // 第 1 次执行结果 => true // 执行完后 myRe.lastIndex 为 6,下一次 test 将从原始字符串下标 6 开始检索 myRe.test(str); // 第 2 次执行结果 => true // 执行完后 myRe.lastIndex 为 13,下一次 test 将从原始字符串下标 13 开始检索 myRe.test(str); // 第 3 次执行 => false // 执行完后 myRe.lastIndex 为 0,下一次 test 将从原始字符串下标 0 开始检索 myRe.test(str); // 第 4 次执行结果 => true // 执行完后 myRe.lastIndex 为 6 let myRe2 = /d(b+)(c*)d/; // myRe2 不携带 g 标志 myRe2.test(str); // 第 1 次执行结果 => true // 执行完后 myRe.lastIndex 为 0,下一次 test 将从原始字符串下标 0 开始检索 myRe2.test(str); // 第 2 次执行结果 => true // 执行完后 myRe.lastIndex 为 0,下一次 test 将从原始字符串下标 0 开始检索 myRe2.test(str); // 第 3 次执行 => true // 执行完后 myRe.lastIndex 为 0,下一次 test 将从原始字符串下标 0 开始检索