实现文本diff比较与展示
作为编程人员,文本diff比较与展示应该不陌生,最常见的是在Git中使用git diff
命令,可以查看代码修改前后的对比。在git中diff比较与展示的最小单位是行,因为代码修改涉及的改动一般较多,以行为单位显示出来的效果,美观且容易阅读。
自己最近在某个项目中遇到与一个git diff类似的需求:“一段普通长度的文本经过修改后,希望向阅读者展示修改所带来的前后差异”,本文就讲述这个需求自己是如何实现的。
分析需求
需求是针对一段普通长度文本展示修改前后的diff,因文本内容较短,所以不选择编码中常见的行作为比较单位,而是以字符为最小单位。进一步分析,可以发现问题的核心是寻找文本修改前后的相同部分,然后再将前后内容与相同部分进行比较,得到差异内容进行可视化呈现。
寻找前后文本中的相同部分,这个描述并不准确,应该是寻找前后文本中长度最长的共同子序列,这个问题的专业名称是“最长公共子序列”,最佳求解方法是使用动态规划求解,具体算法推导详询Google、百度。
假设原文本(before)-“你今天吃饭了吗?”,修改后(after)-“今天你吃饭了吗?”,在这个简单的例子中我们不需要计算也可以看出最长公共子序列(lcs)是:“今天吃饭了吗?”。
接着我们拿before与lcs进行比较,发现差异字符是"你",而after与lcs进行比较得到的差异字符也是"你",但前者表示删除后者则是插入,所以最终我们的diff可以表示为:[“你(delete)”, “今天”, “你(insert)”, “吃饭了吗?”],用这个数组做可视化展示,也就是diff的展示。
最长公共子序列求解
前面的例子由于before与after长度太短,肉眼能看出最长公共子序列,实际中我们则需要用算法与代码实现这部分,思路是先求长度再反推内容,自己用js按算法写了如下实现代码:
function