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

JSON含正则属性时生成相同hashId的原因及处理方案咨询

问题根因

出现这个问题的核心原因是原生JSON.stringify不支持正则表达式的序列化:所有RegExp类型的值在序列化时都会被转成空对象{},和正则本身的匹配规则、修饰符没有任何关系。
你可以直接执行console.log(JSON.stringify(/^INDIA$/i))验证,输出结果就是{}。因此示例中两个对象仅country属性的正则不同时,序列化后的字符串完全一致,最终计算出的SHA256哈希值自然相同。

可行处理方案

方案1:使用JSON.stringify的replacer参数自定义正则序列化

这是成本最低的改法,不需要改动原有逻辑,只需要在序列化时传入自定义替换函数,遇到正则类型时将其转换为可唯一标识的字符串即可:

const crypto = require('crypto');

// 序列化时对特殊类型做转换
const safeReplacer = (key, value) => {
  if (value instanceof RegExp) {
    // 把正则转为 "/规则/修饰符" 格式的字符串,不同正则对应不同字符串
    return `__REGEXP__${value.toString()}`;
  }
  // 有其他特殊类型(比如Date、BigInt)也可以在这里加判断处理
  return value;
};

let j1 = {
  foo: /^hello$/i,
  bar: /^world$/i,
  john: /^1.0$/i,
  country: /^INDIA$/i
};

let j2 = {
  foo: /^hello$/i,
  bar: /^world$/i,
  john: /^1.0$/i,
  country: /^CA$/i
};

let jsonId1 = crypto.createHash('sha256')
  .update(JSON.stringify(j1, safeReplacer))
  .digest('hex');
let jsonId2 = crypto.createHash('sha256')
  .update(JSON.stringify(j2, safeReplacer))
  .digest('hex');

console.log(jsonId1 === jsonId2); // 输出false,哈希可正常区分两个对象

方案2:自定义递归序列化逻辑

如果对象中存在更多JSON原生不支持的类型,或者需要保证键顺序一致避免哈希碰撞,可以自己实现递归序列化逻辑:

  • 遍历对象前先对所有键做排序,保证相同内容不同键序的对象序列化结果一致
  • 遍历属性时按类型做转换:正则取source(规则内容)和flags(修饰符)拼接为唯一字符串、Date转时间戳、undefined/函数/Symbol按业务需求做标记
  • 嵌套对象、数组递归执行上述逻辑

方案3:使用确定性序列化工具

如果业务场景复杂,不想自己维护类型转换逻辑,可以替换原生JSON.stringify为专门处理JS全类型的确定性序列化工具,这类工具会默认处理正则、Date等内置类型,保证同值同序列化结果。

注意事项
  • 只要场景涉及到用序列化结果做哈希、缓存键,都不要直接用原生JSON.stringify处理包含非JSON标准类型(正则、函数、Date、undefined、BigInt、Symbol等)的对象,这类值要么被丢弃,要么被序列化为统一值,非常容易出现碰撞。
  • 如果业务要求「匹配逻辑完全一致的正则生成相同哈希」,直接转字符串的方案无法覆盖写法不同但逻辑等价的正则(比如/\d/和/[0-9]/),这类场景需要额外做正则语法归一化处理,无特殊要求时直接转字符串即可满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:06:26