在本文中,将探讨一种通用的差异比较算法,它能够比较任意类型的对象,并考虑其在ASP.NET Wiki站点中的应用,以实现版本控制和修订跟踪。值得注意的是,尽管作者没有计算机科学学位,也没有深入研究算法设计,但对差异算法有一定的了解。如果读者有任何改进建议或发现作者方向错误,请不吝赐教。
虽然作者对UNIX差异工具等其他差异算法的具体细节不是很清楚,但本文介绍的算法采用了位矩阵和滑动窗口的概念。位矩阵类似于一个棋盘,其中黑色方块表示匹配的项。算法从(0,0)开始,沿着x轴寻找至少两个连续匹配字符的对角线序列。如果找到相同长度的多个序列,算法会选择最近的一个。如果没有找到合适的对角线序列,算法将执行标准操作,比如删除'B'并插入'N',然后更新x和y的位置。
算法的核心是使用一个名为DiffEngine
的类,它使用一个位矩阵来执行比较。这个矩阵的大小和算法的精确度以及内存使用量有关。窗口大小的增加会提高比较的精确度,但同时也会增加内存的使用量和计算时间。在大多数情况下,窗口大小设置为255就足够了。
为了使用这个算法,首先需要创建一个ComparableStreamReader
的子类。这是一个抽象类,它包含一个名为GetNext()
的方法,该方法返回实现了IComparable
接口的对象。在示例中,作者提供了一个名为ComparableStringReader
的类,它逐个返回字符串中的字符。如果需要比较非字符串类型的对象,可能需要创建自定义对象来实现IComparable
接口。
public class ComparableStringReader : Diff.ComparableStreamReader
{
protected string _source;
protected int _location;
public ComparableStringReader(string source)
{
_source = source;
_location = 0;
}
public override IComparable GetNext()
{
if (_location < _source.Length)
return _source.Substring(_location++, 1);
else
return null;
}
}
创建了读取器类之后,接下来需要创建DiffEngine
类的实例。DiffEngine
类有两个属性和一个方法:Compare()
。Compare()
方法接受两个ComparableStreamReader
对象,分别代表源(原始)和目标(已更改的文档)。Compare()
方法返回一个EditScript
对象,这是一个包含DiffCommands
对象的集合。
EditScript
中的每个命令代表需要对源执行的操作,以生成目标文档。命令类型有三种:Insert
、Delete
和Skip
。Skip
和Delete
命令使用DiffCommand
类的Length
属性,而Insert
命令使用Value
属性。Length
属性表示要重复操作的次数,而Value
属性表示要插入的对象,它也是ComparableStreamReader.GetNext()
返回的确切对象。