diff 算法的目标不是理解文本含义,而是找出两个序列里哪些部分相同,哪些部分发生了变化。
实际使用时,先把旧版本放在左侧、新版本放在右侧,再选择适合内容的比较粒度。行级结果适合快速定位段落,词级高亮则负责指出同一行内部究竟改了哪个词。两级结合,既能看到整体结构,也不会漏掉数字、状态或措辞变化。
先看一个可复现的例子
旧版本
Checkout success
Payment pending
Send email receipt
新版本
Checkout success
Payment completed
Send email receipt行级比较会把第二行标记为一处删除和一处新增;词级比较继续在这一行里对齐共同的 Payment,只高亮 pending 与 completed。人工扫长日志时最容易漏掉的,正是这种行结构不变但关键状态已经变化的情况。
基本思路
- 先把文本拆成行、词或字符。
- 寻找两份内容中可以对齐的共同部分。
- 共同部分之间的缺口标记为新增或删除。
- 相邻的删除和新增通常可以被展示为修改。
- 最后把结果渲染成高亮视图。
行级、词级、字符级有什么区别?
| 粒度 | 适合内容 | 特点 |
|---|---|---|
| 行级 | 日志、配置、列表 | 速度快,结构清楚 |
| 词级 | 文案、说明、句子 | 能看出一句话里改了哪个词 |
| 字符级 | 短字符串、标识符 | 很细,但长文本会显得碎 |
| 结构化 | JSON、对象数据 | 按字段路径比纯文本更准确 |
很多 diff 实现会使用最长公共子序列或类似策略。它们尽量保留共同内容,再用最少的插入和删除说明变化。
如何减少无意义的差异
- 先统一换行符与文件编码,避免 Windows CRLF 和 Unix LF 造成整段变化。
- 对日志先去掉每行都会变化的时间戳、请求 ID 或随机值,再比较真正有用的内容。
- 两份 JSON 应改用结构化 JSON 对比,缩进和字段顺序不应该成为差异。
- 整段移动通常会显示为原位置删除、新位置新增,结果并不表示内容被改写。
- 超长文件先按章节或时间范围切小,浏览器更容易计算,人工复核也更聚焦。
把 diff 当作审查线索,而不是结论
算法只能证明文本序列不同,不能判断改动是否正确。审查配置时要确认单位与环境,审查文案时要检查上下文,审查代码生成结果时还要运行对应验证。对于看似只有一个字符的变化,尤其要留意版本号、小数点、负号和权限值。