约 7 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证
三类常见数据的差异语义完全不同。纯文本和代码关心「哪几行变了」,行序本身就是信息;JSON 是键值结构,键的位置没有意义,同一份数据序列化后顺序不同也应视为相等;Markdown 介于两者之间——标题层级和表格结构有意义,但空行和缩进常常只是排版习惯。拿文本对比去做 JSON,会得到一份满屏「删一行、加一行」的噪声;拿 JSON 对比去做 Markdown,又会丢掉表格对齐这类真正想看的差异。
| 对比对象 | 推荐工具 | 对齐依据 | 能忽略的噪音 | 典型输出 |
|---|---|---|---|---|
| 纯文本 / 日志 / 代码 | text-diff | 行号,逐行一一对应 | 行尾空白、大小写、忽略空行 | 红绿高亮的增删块 + 统一 diff |
| JSON 接口返回 / 配置文件 | json-diff | key 路径,数组按 LCS 对齐 | 对象键顺序、数组整体重排 | 字段级增删改 + RFC 6902 Patch |
| Markdown 文档 | html-md 归一化后再对比 | 标题与表格结构 | 排版空行、缩进、列表缩进层级 | 结构化差异视图 |
| 表格型数据(TSV/CSV) | md-table + text-diff | 按单元格位置 | 数字格式、千分位与精度差异 | Markdown 表格 + 差异标记 |
| 多份配置批量核对 | 先文本统计再逐项对比 | key 名 | 注释、字段顺序 | 清单式不一致项 |
12行 log.info("job start, id=1024");
- 13行 log.info("job done");
+ 13行 log.info("job done, cost=83ms");
14行 log.info("exit 0");
统计:新增 1 行 / 删除 1 行 / 修改后总行数 14A: {"a":1,"b":{"c":2,"d":3}}
B: {"b":{"d":3,"c":2},"a":1}
正确结果:无差异(键顺序不参与比较)
错误做法:先字符串化再逐行 diff → 会显示整块都被改写原数组:[{"id":1},{"id":2},{"id":3}]
新数组:[{"id":2},{"id":3},{"id":1}]
按 LCS 对齐:只有 1 项位置变化,读起来是「同一批数据换了顺序」
按下标硬比:3 项全部标记为「改」,噪音量放大三倍同两份文件,开关不同就是完全不同的结论。忽略大小写,适合比较 URL、SQL 关键字、环境变量名这类不区分大小写的场景;忽略全部空白,适合代码格式化后的一致性检查;忽略空行,适合 Markdown 里为了排版随手加的空行。真实冲突是:忽略空白之后,Python 里缩进有意义的代码会显示成「无差异」,但实际上行为完全不同。
这是 JSON 对比最容易出错的地方。数组在语义上有两种:有序的(比如流程步骤、路径)和无序的集合(比如标签、权限列表)。对有序数组,位置变化就是真实变化,必须显示;对无序集合,[a, b, c] 与 [c, a, b] 应当判定为相等。处理办法是给无序集合做键归一:按某个稳定字段(常见是 id)排序后再比,这样顺序噪音就消失了。LCS 对齐是折中方案,它不要求你先声明顺序语义,而是尽量把重排识别成「移动」而不是「删除 + 新增」,代价是输出里会同时出现减少和增加两种标记。
拿到两份不知道该用什么工具的内容时,按这四步走一遍基本不会错。第一步先看数据形状:有嵌套对象和数组就是 JSON,顶部是 # 标题就是 Markdown,剩下的按行看。第一步的输出决定第二步用什么工具:JSON 交给按 key 路径比较的那类,Markdown 先转成统一风格再比,纯文本直接逐行比。第二步是设定噪音规则,规则要显式写出来——「忽略空白后无差异」和「无差异」是两句话,报告给别人时必须带上规则,否则对方无法判断结论的适用范围。第三步在对比前先做一次体检:用文本统计看两侧的行数、字符数、行尾符和是否带 BOM,如果两边体量差一个数量级,先搞清楚是不是拿错了文件,而不是急着逐行看差异。第四步才是读结果,且要先看统计再看细节:先确认「多了几行、删了几处」,再定位到具体位置,顺序反过来容易被第一处无关差异带偏。
很可能是数组顺序造成的。默认按数组下标逐个比较时,一个元素挪位就会让整段都标成「改」。换一个带 LCS 对齐或支持按 id 排序比较的 JSON 对比工具,差异会收敛到真正的字段变化上。
关键是别把 JSON 先压成字符串再逐行比。JSON 对象在语义上无序,用按 key 路径递归比较的对比工具,键顺序不同会判为无差异;先用 JSON 格式化工具规范化也不会解决重排,只是把噪音变得整齐而已。
取决于内容。对 URL、SQL、日志这类空白不敏感的场景很安全;对 Python、YAML 这类缩进有意义的语言则很危险,缩进变了行为就变了,忽略空白会把真实的错误判成无差异。
先用 Markdown 表格生成器把内容对齐成规范表格(补齐分隔行、统一列数),再对这两份规范化结果做逐行对比,差异就会精确落到行和列上。直接对比原始文本会被排版空格干扰。