停止使用 Text Diff 处理 JSON:比较对象的更好方法

发布: (2025年12月12日 GMT+8 23:01)
4 min read
原文: Dev.to

Source: Dev.to

问题:文本 vs. 语义

标准的 diff 算法(比如 Myers 差分算法)是线性的。它们比较字符或行的序列,不理解结构

场景 A(压缩)

如果把一个压缩的 JSON 字符串和一个“美化”后的版本进行比较,即使数据完全相同,也会把每一行都标记为变化。

场景 B(键顺序)

在 JSON 中,对象的键是无序的。然而,JSON.stringify() 会生成键顺序固定的字符串。如果你的后端语言(如 Python 或 Go)在序列化 map 时使用随机的哈希种子,那么每次生成的 JSON 键顺序可能都会不同。

解决方案:语义比较

为了解决这个问题,不能只比较字符串,而必须比较对象本身。

我们在 Diff Guru 提供的工具在真正进行比较之前会执行三步:

  • 验证 – 解析输入字符串,确保它是合法的 JSON。如果你漏掉了逗号,我们会精确指出位置。
  • 规范化(深度排序) – 这就是秘密武器。我们递归遍历对象,并按字母顺序对每个键进行排序。
  • 格式化 – 使用统一的 4 空格缩进对已排序的对象进行美化输出。

只有在完成上述步骤后,才会运行 diff 算法。

工作原理(实现方式)

下面是我们用来确保 { "b": 2, "a": 1 } 在比较前会变成 { "a": 1, "b": 2 } 的简化 TypeScript 代码:

const sortDeep = (o: any): any => {
    // If it's not an object (or is null), return it as is
    if (o === null || typeof o !== 'object') {
        return o;
    }

    // If it's an array, map over the items recursively 
    // (Note: We usually don't sort arrays, as array order often matters!)
    if (Array.isArray(o)) {
        return o.map(sortDeep);
    }

    // It's an object: get keys, sort them, and rebuild the object
    return Object.keys(o).sort().reduce((acc: any, key) => {
        acc[key] = sortDeep(o[key]);
        return acc;
    }, {});
};

通过这段预处理函数,我们过滤掉了由格式和键顺序导致的“噪音”,只保留实际的数据变化

隐私优先(仅客户端)

在构建此工具时,我意识到开发者经常会把敏感数据——API 密钥、用户记录、AWS 配置——粘贴到 diff 工具中。

大多数在线工具会把你的数据发送到后端进行处理。Diff Guru 不会这样做

我们采用 100 % 客户端架构。排序、格式化以及 diff 逻辑(使用 diff‑match‑patch)全部在浏览器的 JavaScript 引擎中运行。你完全可以打开页面后关闭 Wi‑Fi,工具仍能正常工作。你的数据永远不会离开你的机器。

试一试

如果你已经厌倦了手动寻找缺失的逗号或费劲辨别两个庞大 JSON 为什么会被判定为不同,欢迎尝试一下。

👉 尝试 JSON Diff & Validator 工具

免费使用,无需注册,且尊重你的数据隐私。使用后欢迎在评论区告诉我你的感受!

Back to Blog

相关文章

阅读更多 »

继续编码

介绍 我们都有这样的日子:本以为是个简单的修改去修复一个 bug,结果却花了一整天的时间去解决它。如果…