上下文敏感的diff实现

ptp*_*son 7 html algorithm diff vba access-vba

总结和基本问题

使用MS Access 2010和VBA(叹息..)

我正在尝试实现一个专门的Diff函数,它能够根据更改的内容以不同的方式输出更改列表.我需要能够生成一个简明的更改列表,以便为我们的记录提交.

我想使用诸如html标签之类的东西,<span class="references">These are references 1, 6</span>以便我可以使用代码查看更改并自定义更改文本的输出方式.或其他任何东西来完成我的任务.

我认为这是一种提供自定义输出的可扩展方式的方法,并可能将事物移动到更强大的平台并实际使用html/css.

有谁知道一个类似的项目可能能指出我正确的方向?

我的任务

我有一个访问数据库,其中包含工作操作指令表 - 通常是200-300个操作,其中许多操作从一个修订版更改为另一个修订版.我目前已经实现了一个迭代表的函数,查找已更改的指令并进行比较.

请注意,每个操作指令通常是几个句子,最后有几行,带有一些文档引用.

我的算法基于"An O(ND)差分算法及其变化",效果很好.

Access支持"Rich"文本,这只是美化简单的html,因此我可以轻松生成带有格式化添加和删除的全文,即添加标签<font color = "red"><strong><i>This text has been removed</i></strong></font>.Diff过程的主要输出是操作的全文,其中包括彼此内联的未更改,已删除和插入的文本.diff过程添加<del><ins>标签稍后将替换为格式化文本(结果类似于堆栈交换编辑的更改视图).

但是,就像我说的,我需要以人类可读格式列出的更改.事实证明这很困难,因为许多变化产生了模糊性.

例如:如果某种化学品从"A类"变为"C类",则容易生成的更改文本是"将'A'更改为'C'",这对于审核该类型的人来说并不是非常有用.变化.更常见的是文档参考结尾:将SOP 3添加到列表中,例如"SOP 1,2,3",生成文本"添加'3'".显然也没用.

最有用的是指定为"SOP"文本的文本的自定义输出,以便输出为"添加对SOP 3的引用".

我从以下解决方案开始:

将单词组合在一起,例如将诸如"SOP 1,2,3"的文本作为一个标记来进行比较.这将生成文本"将'SOP 1,2'改为'SOP 1,2,3'.当存在大型列表并且您试图确定实际更改的内容时,这会变得混乱.

我现在在哪里

我现在正在尝试在运行diff算法之前添加额外的html标签.例如,我将通过"预处理器"运行文本,将"SOP 1,2"转换为SOP 1,2

一旦Diff过程返回完整的更改文本,我会浏览它,注意文本的当前"类",当有一个<del><ins>我捕获标记之间的文本并使用SELECT CASE类上的块来解决每个更改.

这实际上在大多数情况下都可以正常工作,但是我必须解决许多问题,例如添加Diff决定最短路径是删除某些开放标记并插入其他开放标记.这会创建一个场景,即有两个<span>标签,但只有一个</span>标签.

最终的问题

我正在寻找建议,要么继续我已经开始的方向,要么在投入更多时间进入次优解决方案之前尝试不同的方法.

在此先感谢所有人.

另请注意:

典型运行的时间大约是1.5到2.5秒,我尝试了更多花哨的东西和一堆debug.prints.因此,通过一两个额外的通行证不会是杀手.

Gen*_*ene 3

尝试考虑 Prolog 风格的重写规则,将您的指令转换为规范形式,从而使 diff 算法产生您需要的内容。您指定的问题将通过以下规则解决:

SOP i1, i2, ... iN  ->  SOP j1, SOP j2, ... SOP jN  where j = sorted(i)
Run Code Online (Sandbox Code Playgroud)

换句话说,将 SOP“分布”到以下整数的排序列表上。这将欺骗 diff 算法给出完全合格的变更报告“Add SOP 3”。

通过在输入中搜索左侧的匹配项并替换为相应的右侧来应用规则。

您可能已经这样做了,但是如果输入被标记化,您将获得更多常识性分析:“SOP”应该被视为 diff 算法的单个“字符”。如果空白很重要,则可以将其减少为空格和换行符,否则将被忽略。

您可以在字符级别执行另一种差异,以测试标记的“模糊”相等性,以解决匹配左侧时的印刷错误。“SIP”和“SOP”将被视为“匹配”,因为它们的编辑距离仅为 1(并且 I 和 O 在 QUERTY 键盘上仅相距一个键!)。

如果您考虑现在得到的输出中的所有怪癖,并且可以将每个怪癖作为重写规则进行纠正,该重写规则将输入转换为 diff 算法生成您需要的内容的形式,那么剩下的就是实现重写系统。以有效的通用方式执行此操作,以便更改和添加规则不会涉及大量的临时编码,这是一个困难的问题,但已经被研究过。有趣的是,@Ira Baxter 提到了 lisp,因为它非常适合作为此类事情的工具。

Ira 对语法树的建议很自然地属于重写规则方法。例如,假设 SOP 有部分和段落:

SOP 1 section 3, paras 2,1,3
Run Code Online (Sandbox Code Playgroud)

是一个层次结构,应该重写为

SOP 1 section 3 para 1, SOP 1 section 3 para 2, SOP 1 section 3 para 3
Run Code Online (Sandbox Code Playgroud)

重写规则

paras i1, i2, ... iN  ->  para j1, para j2, ... para jN  where j = sorted(i)
section K para i1, ... para iN  ->s section K para j1, ... section K para j1
SOP section K para i1, ... section K para i1 -> SOP section K para j1, ... SOP section K para j1 
Run Code Online (Sandbox Code Playgroud)

当应用三遍时,将产生类似“SOP 1 第 3 部分,第 4 段已添加”的结果。

虽然实现规则和重写的策略有很多,包括将每个策略编码为 VB 中的过程(呃……),但还有其他方法。Prolog 是尽可能普遍地做到这一点的一次伟大尝试。 有一个免费的实施。 还有其他的。我已经使用TXL完成了有用的重写。TXL 的唯一问题是它假设您对输入有相当严格的语法,但这听起来不像您的问题中的情况。

如果您在当前输出中发布更多怪癖示例,我可以跟进有关重写规则的更多详细信息。