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

JavaScript中如何判断两个含通配符的正则表达式是否匹配

问题根因

原有实现的逻辑存在本质缺陷:双向调用.test()是拿一个模式的字面字符串去匹配另一个模式,仅能覆盖「一个模式完全包含另一个模式」的场景,无法识别两个模式存在交叉公共匹配串、但互相不能匹配对方模式字面量的情况。
以失败用例为例:

  • john:alex:* 转成正则后匹配所有以john:alex:开头的字符串
  • john:*:doe 转成正则后匹配所有以john:开头、以:doe结尾的字符串
    两个模式存在大量公共匹配串(比如john:alex:doe),按预期应该返回true,但原有逻辑测试时会把模式里的*当做普通字符处理,两次测试都返回false,最终得到错误结果。
    另外原有toRegex方法存在转义bug:替换特殊字符时的\\$&是HTML转义残留,正确写法应为\\$&,否则会在转义后的特殊字符后多余拼接amp字符串。
改进实现

判断两个带通配符的模式是否匹配,核心是判断是否存在至少一个字符串能同时被两个模式匹配,也就是求两个模式的匹配集合是否存在交集。针对通用通配符规则(*匹配任意长度任意字符、?匹配单个任意字符),用动态规划直接做两个模式的交集判断,比正则互测覆盖场景更全,代码如下:

/**
 * 判断两个通配符模式是否存在匹配交集
 * @param {string} p 第一个通配符模式
 * @param {string} q 第二个通配符模式
 * @returns {boolean} 存在公共匹配返回true,否则返回false
 */
const compare = (p, q) => {
  const m = p.length, n = q.length;
  // dp[i][j] 表示p的前i个字符、q的前j个字符是否存在公共匹配串
  const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(false));
  // 两个空串天然匹配
  dp[0][0] = true;

  // 处理模式开头为连续*的边界情况
  for (let i = 1; i <= m; i++) {
    if (p[i - 1] === '*') dp[i][0] = dp[i - 1][0];
  }
  for (let j = 1; j <= n; j++) {
    if (q[j - 1] === '*') dp[0][j] = dp[0][j - 1];
  }

  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      const pc = p[i - 1], qc = q[j - 1];
      if (pc === qc || pc === '?' || qc === '?') {
        // 当前字符相等或为单字符通配符,结果继承前一位的匹配状态
        dp[i][j] = dp[i - 1][j - 1];
      } else if (pc === '*') {
        // p侧为多字符通配符:要么*匹配空串,要么*吃掉q侧当前字符
        dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
      } else if (qc === '*') {
        // q侧为多字符通配符:要么*匹配空串,要么*吃掉p侧当前字符
        dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
      } else {
        // 当前字符都是普通字符且不相等,无匹配可能
        dp[i][j] = false;
      }
    }
  }

  return dp[m][n];
};
效果验证
// 原有正常用例
const a1 = 'john:alex:*';
const b1 = 'john:*';
console.log(compare(a1, b1)); // true

// 原有失败用例
const a2 = 'john:alex:*';
const b2 = 'john:*:doe';
console.log(compare(a2, b2)); // true

// 其他边界用例
console.log(compare('a*c', '*b*')); // true 公共串abc
console.log(compare('a*b', 'c*d')); // false 无公共串
console.log(compare('*.txt', 'a*')); // true 公共串a.txt
console.log(compare('a?c', 'a*')); // true 公共串abc、adc等

如果需要保留通配符转正则的能力,修复转义bug后的toRegex方法如下:

const toRegex = (str) =>
  new RegExp(
    '^' +
      str
        .replace(/[\-\[\]\/\{\}\(\)\+\.\\\^\$\|]/g, '\\$&')
        .replace(/\*/g, '.*')
        .replace(/\?/g, '.') +
      '$',
  );

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 07:31:27