linux的diff工具原理之Myers算法
前言
最近在看一些软件演化相关的论文,当然,对于这个领域我是第一次接触的,非常多的东西不懂得,所以只有顺着论文开始一点点向下的学会其中的东西。
我看的是ICSE2021的论文,名为《A Differential Testing Approach for Evaluating
Abstract Syntax Tree Mapping Algorithms》,不过再看完之后,我产生了比较多的问题的,我虽然学过编译原理,但是我还是第一次知道一个代码AST居然不是唯一的,并且根据不同的算法生成的AST居然有优劣之分,这让我非常的好奇。
不过,在我写这篇文章之前,这个好奇并还没有被我解决的,因为在看ICSE2021这篇文章的时候,我发现我并不清楚论文中所比对的三个算法:GumTree、MJDiff和IJM(Iterative Java Matcher)
所以我找到了论文引用的对于这三个算法的原论文进行阅读,这一篇就是在阅读GumTree的时候所需要了解的一个算法。
GumTree算法的原论文名称《Fine-grained and Accurate Source Code Differencing》。
而GumTree和Myers算法有什么关系呢?两者都是一种diff算法,也就是对于软件演化计算出编辑脚本(edit script)的一个算法(diff 就是目标文本和源文本之间的区别,也就是将源文本变成目标文本所需要的操作。),只不过Myers应该算是最基础的一个算法了,而GumTree应该是加入了树形结构相关的东西。
而且我在查阅学习Myers算法的时候,意外的发现了,Myers算法也是Linux常用diff工具的原理(git的diff原理也是这个。)
那么接下来就是对Myers算法的介绍了。
diff
上面也说了diff 就是目标文本和源文本之间的区别,也就是将源文本变成目标文本所需要的操作。
如果用过diff工具的人应该会比较了解,在github中对于新增加的行在GUI中会用对该行标绿并打上一个+号,对于删减行会对该行标红并且打上一个-号。
看上去功能好像挺简单的样子,但是实际上要实现这一个功能是一个非常复杂的问题。
比如:源文本为 ABCABBA,目标文本为 CBABAC,他们之间的 diff 其实有无穷多种(我们以字符为单位,一般情况下是以行为单位)。
上面三种都是有效的diff,但是给人的感官不一致,切确的来说第一种给人的感觉是最良好的,给人的感觉最为直观。
“直观”其实是一个非常主观的定义,不过要满足这个条件我们其实可以猜到的:
- 删除后新增,比新增后删除要好
- 当修改一块代码时,整块的