在本文中,将探讨如何比较两个文本文件并识别它们之间的差异。这涉及到一个著名且高效的算法,该算法首次由Eugene Myers在1986年提出,并发表在《Algorithmica》杂志上。将介绍一个简单的类实现,它提供了一个易于使用的API来完成这项工作。此外,还将提供一个示例Web应用程序,该程序比较两个文件并生成带有合并和着色的HTML输出文档。
算法最初由Eugene Myers在1986年发表,题为"An O(ND) Difference Algorithm and its Variations"。尽管有许多C、Java和Lisp的实现版本,但大多数都来源于GNU diffutils,并且受到GNU公共许可证的限制,不能在商业或可重分发的应用程序中使用。因此,从头开始实现了原始算法,并在Creative Commons Attribution 2.0 Germany License下提供,以避免GNU许可证的限制。
比较两个大型文本文件的字符并非易事,且往往效率低下。因此,算法的第一步是为所有文本行计算唯一的数字。如果文本行相同,则计算出相同的数字。在计算这些数字之前,需要考虑一些选项,这些选项通常对某些类型的文本很有用,比如去除空格字符和不区分大小写的比较。
核心算法本身将比较两个数字数组,准备工作在私有的DiffCodes方法和使用Hashtable中完成。DiffText和DiffInts是核心方法。算法的核心构建使用了两个方法:LCS(最长公共子序列的分治实现)和SMS(寻找最短中间蛇形)。为了获得可用的性能,对原始算法进行了一些更改。原始算法使用递归方法描述,比较零索引序列,并将这些序列的部分作为参数传递。为了避免在数组之间复制这些序列,使用了数组以及它们的下界和上界,而不是一直复制序列。这使得LCS和SMS函数更加复杂。
要使用此功能,只需调用DiffText方法之一即可。它们都接受一对字符串,并返回描述两个字符串之间插入和删除的项数组。没有报告"更改",而是可以找到"插入"和"删除"对。
示例是一个小型Web应用程序,它计算两个文本文件之间的差异,并使用HTML显示结果。要设置示例,需要创建一个Web项目,并将zip文件中的所有文件复制到目录中。算法的实现在diff.cs类中提供。
如果确实需要速度,可以进行一些优化。例如,DataA和DataB数组作为参数传递,但在创建后从未更改,因此可以作为类的成员使用,以避免参数开销。在SMS中,有很多边界算术在for-D和for-k循环中,可以通过递增和递减局部变量来完成。DownVector和UpVector数组每次调用SMS时都会创建和销毁。将它们转移到类的成员中是可能的。
使用此Web站点实现允许客户端查看网站的源代码。请确保不要在公共服务器上直接使用它。应该实现参数检查,并仅允许显示文本文件的diff输出。
本作品在Creative Commons Attribution 2.0 Germany License或BSD-3-Clause许可下授权。
该类现在具有内置的自测试,无需更改代码即可工作。如果将diff和debug类文件一起编译,将得到一个EXE文件,该文件测试了一些简单的diff场景,这些场景用于发现版本1和2中的错误(通常是数组越界错误)。