关于正则编写的细节这里不多做赘述,本文主要是列出 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 开始检索