正则表达式带有全局表示/g时引起的多次返回不一致的原因解析

96 阅读2分钟
  1. 现象:两次执行结果不一致
const reg = /\s/g; //校验是否有空格
function regTestFun(str) {
    console.log(reg.test(str));
}
regTestFun('12 34') // true
regTestFun('12 34') // false
  1. 原因:

    • 使用带有全局标志的正则表达式进行匹配时,它会在字符串中查找所有的匹配项,并将当前匹配的结束位置保存在 lastIndex 属性中。下一次使用同一个正则表达式对象进行匹配时,它会从 lastIndex 指定的位置开始搜索。
    • 正则表达式 reg 使用了全局标志 g,会保留之前的匹配位置。连续多次调用 regTestFun('12 34') 方法时,每次调用中的 reg.test(str) 都会从上一次匹配结束的位置开始,而不是从字符串的开头。
  2. 解决

    • 删除正则中的/g(但是会出现只会匹配第一个,不满足需求)----不建议
    • 在每次调用完regTestFun后,重置reg.lastIndex = 0;(在实际项目中,往往会把正则写在一个专门的正则js文件中,而regTestFun调用一般在业务代码中,在业务代码中添加reg.lastIndex = 0;显然不合理) ----不建议
// 建议使用方式
// 全局正则汇总ts文件
function createRegex(pattern: RegExp | string, flag = ''): RegExp {
    return new RegExp(pattern, flag);
}
export const reg = createRegex(/\s/g);
  1. 结论:
    • 使用testmatchreplace都会出现这种情况
    • 通过使用函数createRegex封装正则表达式并在每次使用时动态创建新的正则表达式对象,可以避免全局标志 g 导致的结果不一致问题。
    • 不使用全局标志 g:正则表达式在找到第一个匹配项后停止,并返回结果。下一次匹配将从上次匹配的结束位置开始。
    • 使用全局标志 g:正则表达式会尝试在整个字符串中找到所有匹配项,并返回所有结果。下一次匹配将从上次匹配的结束位置继续,而不是从字符串的开头。
// 使用`g`和不使用 `g`的代码示例
const str = "abcabcabc";
const regexWithoutG = /abc/;
const regexWithG = /abc/g;

console.log(str.match(regexWithoutG)); // 输出:["abc"]
console.log(str.match(regexWithG)); // 输出:["abc", "abc", "abc"]