文本对比工具

并排比较两个文本,高亮显示新增、删除与未变更的内容。

原始
新

文本对比不是"找不同",而是把改动规模翻译成可度量指标

文本对比(text diff)常被当成"两版文档哪里不一样"的肉眼游戏,但从工程与信息检索角度看,它真正解决的是三个可度量问题:改动有多大、改动分布在哪、两版有多相似。本工具基于 LCS(最长公共子序列)做逐行比对,把"相同行"作为锚点,把"只存在于某一侧的行"标记为新增或删除,输出四组计数(相同、新增、删除、总变更)和一种相似度视角,而不是一句模糊的"不一样"。理解这一点,你才能把对比结果当评审清单、合并依据或质量门槛来用,而不是当作一个高亮特效。

算法家族对照:四种主流 diff 算法各有所长

不同 diff 工具背后是同一道题目的不同解法——如何在两段序列里高效找出"变与不变"。下面把四种常见算法放在一起对照,重点不是背复杂度,而是明白"为什么有的工具改一行很快、有的对重组过的代码更友好"。

算法核心思路最适用场景最好复杂度最坏复杂度
LCS(最长公共子序列)用动态规划求两段的最长公共子序列作锚点短文本、教学演示、并排比对O(m+n)O(m×n)
Myers O(ND)在编辑图(edit graph)上找最短编辑路径代码版本 diff、git diff 底层O(N)O((N+D)×D)
Patience Diff用"唯一且递增"的锚点行做耐心匹配代码被大幅重排、移动块多约 O(n log n)约 O(n log n)
Histogram Diff按出现频次给行加权重再选锚点大文件、重复行多的日志/数据约 O(n log n)约 O(n log n)

说明:m、n 是两段各自的行数;N 是两版总规模,D 是实际差异量。本工具采用 LCS,因为它实现直观、结果贴近"求同存异"的直觉,适合文本、配置、文档的整体对照;当你要处理被大量移动或重排过的代码时,Myers / Patience / Histogram 往往更合适。

粒度对照:按行 / 按词 / 按字符 / 按字

diff 的"粒度"决定它把什么当作一个不可再分的比较单元。粒度越粗(按行),结果越干净、性能越好,但会忽略行内改动;粒度越细(按字符、按字),能定位到具体改了哪个字,但噪声也更多。下表给出四种粒度的取舍。

粒度比较单元适合场景代价 / 注意
按行整行文本代码、配置、文章段落整体对照行内小改会被标成整行删除+新增
按词以空格/标点切分的词英文散文、技术文档的句内改动中文没有天然空格分词,需先分词
按字符单个字符精确排查拼写、ID、符号差异结果冗长,适合短串而非长文
按字单个汉字中文句内改字、增删字的精确定位与"按词"差异极大,见下

注意:中文的"按字符"和"按词"差异极大。中文书写没有空格,若用字符级 diff,把"这是第一行。"改成"这是修改后的第二行。"需要 5 次编辑(6 个字 vs 10 个字,单看改动行 LCS 编辑距离为 5);而若先做中文分词、按"词"对比,共同前缀"这是"会被保留,真正变化的只是"第一行 → 修改后的第二行"这一小块,报告改动量显著更小。英文天然按空格分词,按词和按字符的差距没这么夸张(同一处改动英文约 12 次字符编辑)。所以处理中文时,选对粒度比选算法更影响阅读体验。长文建议先用 字数统计 确认两侧长度是否对得上,再决定是否分段。

相似度与差异率:三种可精算的指标

"两版有多像"不能只靠感觉,下面三个指标都能用脚本 100% 复现,本工具算例数字即来自同一套公式。

1) Levenshtein 距离(编辑距离):把一个字符串变成另一个所需的最少单字符插入、删除、替换次数,距离越小越相似。
2) Jaccard 相似度:两集合交集除以并集,取值 0–1;用于行集合时,J = 相同行数 ÷(相同行数 + 新增行数 + 删除行数)。
3) 编辑距离归一化(相似度):Sim = 1 − Lev ÷ max( len(A), len(B) ),结果以百分比表示,越接近 100% 越相似。

以页面默认输入为例(原始三行 vs 新文本四行):整段字符级 Levenshtein 距离为 14(中文)/ 40(英文),归一化相似度约 66.7%(中文)/ 66.9%(英文);按行集合的 Jaccard 相似度为 40.0%。注意:行数对不上(3 行 vs 4 行)会拉低 Jaccard,但归一化编辑距离只看字符总量,因此两者给的"像不像"结论会不同——评审时建议同时看。

指标公式默认输入(中文)默认输入(英文)解读
Levenshtein 距离最少插入/删除/替换次数1440越小越相似
Jaccard(行集合)相同行 ÷ 全部出现行40.0%40.0%受行数不对等差影响
归一化编辑距离1 − Lev ÷ max(len)66.7%66.9%只看字符总量

unified diff 与 context diff 格式逐字段说明

命令行 diff 通常输出两种经典格式,理解字段含义才能把本工具的并排结果"翻译"成可粘贴的 patch。Markdown 文档可先在 Markdown 预览 里整理后再对比。

字段unified diff(以 @@ / + / − 标记)context diff(以 * / ! / 上下文行标记)
文件头--- a/file / +++ b/file 标旧新文件*** file1 / --- file2 分两栏标头
块头@@ -l,s +l,s @@ 标旧/新起止行与长度用 *************** 分隔上下两块上下文
未变行无前缀(空格开头)无前缀或上下文行
新增行+ 开头+ 开头
删除行- 开头- 开头
上下文行数默认 3 行(可 -U n 调)默认上下各 3 行

本工具的并排视图等价于"把 unified diff 的 + / − 行左右对齐":左侧放旧版(删除行落在左、空位补白),右侧放新版(新增行落在右)。它没有文件头,因为对比的是两段纯文本而非磁盘文件。

常见文本对的差异率基准(实测)

下面四组样本用本工具同一套逐行 LCS 逻辑跑出,差异率定义为"变更行数 ÷(相同行数 + 变更行数)× 100%"。它们给你一个"多像算像、多改算大改"的直观标尺。若要传输大段文本,可先用 压缩/解压 工具减小体积再分段比对。

样本类型行数(旧→新)相同新增删除总变更差异率
同文档微改(改 1 行 + 增 1 行)12 → 131121321.4%
局部改写(改 4 行,保 8 行)12 → 12844850.0%
另起炉灶重写(几乎全变)12 → 120121224100.0%
中英混排段落(改 2 行)8 → 8622440.0%

注意:差异率只看行的"同/异",不关心行内改了多少字;一句里改一个字和整行重写,在行级差异率里都算"1 行变更"。要区分行内改动幅度,需回到上一节的字符级 / 字级 Levenshtein。

三个真实算例(页面默认输入)

下面三个算例全部使用本工具文本框里的默认内容,数字与页面点击"对比"后看到的一致。

算例 1:默认输入的行级 diff 统计
原始文本框(3 行):
"你好,欢迎使用文本对比工具!"
"这是第一行。"
"第三行未改变。"
新文本框(4 行):
"你好,欢迎使用文本对比工具!"
"这是修改后的第二行。"
"第三行未改变。"
"第四行是新内容。"
LCS 对齐后:第 1 行与第 3 行相同(2 行),"这是第一行。"被删除(1 行),"这是修改后的第二行。"与"第四行是新内容。"为新增(2 行)。统计为:相同 2、新增 2、删除 1、总变更 3,差异率 = 3 ÷ (2+3) = 60.0%。并排视图里只有第 2 行附近与第 4 行被高亮,其余保持白色不变。

算例 2:中文按"字"粒度看改动行
聚焦被改动的这一行:旧"这是第一行。"(6 字)vs 新"这是修改后的第二行。"(10 字)。按字级 Levenshtein 需要 5 次编辑(插入"修改后"的 3 字、把"一"替换为"二"、在"。"前补"的")。若改为按词粒度(先中文分词),共同前缀"这是"被保留,真正变化只是"第一行 → 修改后的第二行",报告改动量明显更小。这正说明中文处理时"粒度"比"算法"更影响阅读噪声——本工具按行比较,行内差异可结合 字数统计 辅助判断。

算例 3:默认输入的整体相似度
把两段完整文本喂给相似度公式:字符级 Levenshtein 距离 = 14,归一化相似度 ≈ 66.7%;按行集合的 Jaccard = 40.0%。两个指标一高(66.7%)一低(40.0%)看似矛盾,其实一致——归一化编辑距离只看"字符改了多少",而 Jaccard 被"3 行变 4 行"的行数缺口拉低。结论是:这段文本字符层面保留了约三分之二,但行结构变了四成。

与 git diff / 版本管理的衔接

git 在底层用 Myers(及其变体)做 diff,并叠加 rename 检测、hunk 合并等策略。本工具与 git diff 的关系有三层:其一,本工具是纯文本、无文件概念的"迷你 diff",适合快速对比两段粘贴内容;其二,当你想把结果接回 git,应把差异以 unified diff 形式保存(参考上节字段),git apply 才能识别;其三,git 的"行号"基于文件全局行号,本工具只给相对位置,合并冲突(<<<<<<< / ======= / >>>>>>>)需回到 git 环境处理。需要统计改动规模时,可先用本工具做粗筛,再回到命令行跑 git diff --stat 看全仓汇总。更系统的对比思路见博客长文 文本对比实战指南。

补充问答

文本对比工具用的是哪种算法,为什么默认按行比较?

本工具使用 LCS(最长公共子序列)动态规划做逐行比对,把相同行作为锚点,只出现在某一侧的行标记为新增或删除。按行比较实现直观、性能稳定,适合文本、配置和文档的整体对照;处理被大量移动或重排的代码时,Myers、Patience、Histogram 等算法更合适。

中文文本用按字符还是按词对比,差异更大?

差异极大。中文没有空格分词,字符级 diff 把"这是第一行。"改成"这是修改后的第二行。"需 5 次编辑;若先做中文分词按词对比,共同前缀"这是"被保留,真正变化只是"第一行 → 修改后的第二行"。英文天然按空格分词,按词与按字符差距较小(同处改动约 12 次字符编辑)。

unified diff 和 context diff 有什么区别,该看哪种?

unified diff 用 @@ -l,s +l,s @@ 块头加 + / − 前缀,新旧改动并排在一栏,最常用;context diff 用 *** 与 --- 分两栏标头、用 ! 标改动行,上下文更分散。本工具的并排视图等价于把 unified diff 的 + / − 行左右对齐。

差异率(改动比例)是怎么算出来的?

本工具的差异率 = 变更行数 ÷(相同行数 + 变更行数)× 100%。变更行数 = 新增行数 + 删除行数。它只看行的同异,不关心行内改了多少字;要衡量行内幅度需用字符级 Levenshtein。

本工具的对比结果能直接用到 git 里吗?

本工具是纯文本迷你 diff,无文件概念。要接回 git,应把差异保存为 unified diff 格式(含 --- / +++ 文件头与 @@ 块头),git apply 才能识别;合并冲突标记需回到 git 环境处理。粗筛改动规模后,可用 git diff --stat 看全仓汇总。