You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RegExp.prototype.exec()无限循环问题及Node.js环境下的预防咨询

如何避免用户自定义正则导致的无限循环

核心问题原因

当使用带g标志的正则时,exec方法会通过lastIndex属性记录下一次匹配的起始位置。如果正则匹配到零宽度内容(比如.*匹配空字符串、^行首、$行尾等),且匹配后lastIndex没有自动推进(空匹配场景下默认不会递增),就会导致每次exec都在同一位置重复匹配,陷入无限循环。

可行解决方案

1. 静态检测正则的潜在风险

提前分析用户输入的正则表达式,识别可能引发循环的模式:

  • 检查是否同时存在g标志和可匹配空字符串的模式(如.*、.?、[a-z]*、^、$等)
  • 对这类正则,要么禁止使用g标志,要么在匹配逻辑中添加防护逻辑

2. 在匹配循环中强制推进索引

修改匹配逻辑,当检测到零宽度匹配时,手动递增lastIndex,避免重复匹配同一位置:

const regex1 = RegExp('.*', 'g');
const str1 = 'text';
let array1;

while ((array1 = regex1.exec(str1)) !== null) {
  console.log(array1.index);
  // 处理零宽度匹配,强制推进索引
  if (array1[0].length === 0) {
    regex1.lastIndex++;
    // 到达字符串末尾时终止循环
    if (regex1.lastIndex > str1.length) break;
  }
}

3. 改用非全局匹配(业务允许的话)

如果不需要遍历所有匹配结果,去掉g标志,用match方法一次性获取匹配结果,避免手动循环的风险:

const regex1 = RegExp('.*');
const str1 = 'text';
const matches = str1.match(regex1);
console.log(matches);

4. 给正则匹配添加超时限制

在Node.js中,用Worker线程包装正则执行逻辑,添加超时机制,防止整个进程挂起:

const { Worker } = require('worker_threads');

function runRegexWithTimeout(regexStr, flags, input, timeout = 5000) {
  return new Promise((resolve, reject) => {
    const worker = new Worker(`
      const { parentPort } = require('worker_threads');
      const regex = new RegExp(${JSON.stringify(regexStr)}, ${JSON.stringify(flags)});
      const result = [];
      let match;
      while ((match = regex.exec(${JSON.stringify(input)})) !== null) {
        result.push(match);
      }
      parentPort.postMessage(result);
    `);

    const timeoutId = setTimeout(() => {
      worker.terminate();
      reject(new Error('正则匹配超时'));
    }, timeout);

    worker.on('message', (result) => {
      clearTimeout(timeoutId);
      resolve(result);
    });

    worker.on('error', (err) => {
      clearTimeout(timeoutId);
      reject(err);
    });
  });
}

// 使用示例
runRegexWithTimeout('.*', 'g', 'text')
  .then(matches => console.log(matches))
  .catch(err => console.error(err));

5. 使用安全正则检测库

借助第三方库(如safe-regex)提前检测正则的性能风险,拦截危险表达式:

const safeRegex = require('safe-regex');

const userRegex = new RegExp('.*', 'g');
if (!safeRegex(userRegex)) {
  throw new Error('该正则表达式存在性能风险,无法执行');
}

内容的提问来源于stack exchange,提问作者Jatin Sanghvi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 19:30:49