将diff-patch应用于字符串/文件

Fel*_*ala 5 ruby diff merge smartphone

对于具有脱机功能的智能手机应用程序,我正在为Xml文件创建单向文本同步.我希望我的服务器将delta /差异(例如GNU diff-patch)发送到目标设备.

这是计划:

Time = 0
Server: has version_1 of Xml file (~800 kiB)
Client: has version_1 of Xml file (~800 kiB)

Time = 1
Server: has version_1 and version_2 of Xml file (each ~800 kiB)
        computes delta of these versions (=patch) (~10 kiB) 
        sends patch to Client (~10 kiB transferred)

Client: computes version_2 from version_1 and patch  <= this is the problem =>
Run Code Online (Sandbox Code Playgroud)

是否有一个Ruby库可以执行最后一步,将文本补丁应用于文件/字符串?可以根据库的要求格式化补丁.

谢谢你的帮助!

(我使用的是Rhodes跨平台框架,它使用Ruby作为编程语言.)

mu *_*ort 6

您的首要任务是选择补丁格式.人类最难阅读的格式(恕我直言)证明是最容易应用的软件格式:ed(1)脚本.您可以从简单的方法/usr/bin/diff -e old.xml new.xml开始生成补丁; diff(1)将产生面向行的补丁,但开始时应该没问题.ed格式如下所示:

36a
    <tr><td class="eg" style="background: #182349;">&nbsp;</td><td><tt>#182349</tt></td></tr>
.
34c
    <tr><td class="eg" style="background: #66ccff;">&nbsp;</td><td><tt>#xxxxxx</tt></td></tr>
.
20,23d
Run Code Online (Sandbox Code Playgroud)

数字是行号,行号范围用逗号分隔.然后有三个单字母命令:

  • a:在此位置添加下一个文本块.
  • c:将此位置的文本更改为以下块.这相当于一个d后跟一个命令.
  • d:删除这些行.

您还会注意到补丁中的行号是自下而上的,因此您不必担心更改会在补丁的后续块中弄乱行号.要添加或更改的实际文本块遵循命令,作为由具有单个句点(即/^\.$/patch_line == '.'取决于您的偏好)的行终止的一系列行.总之,格式如下所示:

[line-number-range][command]
[optional-argument-lines...]
[dot-terminator-if-there-are-arguments]
Run Code Online (Sandbox Code Playgroud)

因此,要应用ed补丁,您需要做的就是将目标文件加载到一个数组中(每行一个元素),使用一个简单的状态机解析补丁,调用Array#insert添加新行和Array#delete_at到删除它们.不应该使用超过几十行Ruby来编写修补程序,并且不需要库.

如果您可以安排您的XML出现如下:

<tag>
blah blah
</tag>
<other-tag x="y">
mumble mumble
</other>
Run Code Online (Sandbox Code Playgroud)

而不是:

<tag>blah blah</tag><other-tag x="y">mumble mumble</other>
Run Code Online (Sandbox Code Playgroud)

那么上面简单的面向行的方法就可以了; 额外的EOL不会花费太多空间,因此可以轻松实现.

有两个用于在两个数组之间产生差异的Ruby库(谷歌"ruby algorithm :: diff"开始).将diff库与XML解析器结合使用,可以生成基于标记而非基于行的补丁,这可能更适合您.重要的是补丁格式的选择,一旦你选择了ed格式(并且实现了从底部到顶部的补丁的智慧),那么其他所有东西都很容易实现.