带差分的字符串压缩

时间:2012-09-02 22:09:33

标签: ruby string compression diff

我正在考虑在Ruby中压缩一些非常大的字符串(文本字段),然后将它们插入到数据库blob字段中。压缩本身很容易,我可以使用Zlib。

但是,我也在查看可能有类似字符串副本的情况。例如。我可能已经在数据库中存储了一些东西 - stringA。修改给了我stringB。我想存储stringA和stringB之间差异的压缩版本,这样如果我有stringA和压缩差异,我可以得到stringB。

是否有合适的库?

理想情况下,它将是单步二进制差异压缩。我真的不想要一个人类可读的文本差异(这可能会浪费更多的空间)。它只需要机器可读。因此,请不要建议我使用diff -u oldFile newFile > mods.diffpatch < mods.diff进行压缩。

答案

编辑:感谢Mark Adler部分答案(不知道有set_dictionary方法)。我想在Ruby中执行此操作,因此,相关的方法名称为set_dictionary。然而,试图完成这项任务比没有字典要困难得多。

不使用字典,我们可以这样做:

A = "My super string to be compressed. Compress me now to " \
    "save the space used to store this super string."
cA = Zlib::Deflate.deflate(A)
# => "x\234U\214\301\r\200 \020\004[\331\nh\302\267E n\224\a\034\271;4v..."

Zlib::Inflate.inflate(cA)
# => "My super string to be compressed. Compress me now to save the..."

但是要使用字典,您需要确保传递Zlib::FINISH以进行deflate以刷新输出,并在膨胀时添加字典之前允许Zlib::NeedDict例外:

B = "A super string with differences, let's see how much " \
    "extra space the differences will take in this super string!"
zlib_deflate = Zlib::Deflate.new
zlib_deflate .set_dictionary(A)
dB = zlib_deflate .deflate(B, Zlib::FINISH)
# => "x\2733\324$\230sD\265\242<\263$C!%3--\265(5/9\265XG!'\265D\035\250..."

zlib_inflate = Zlib::Inflate.new
zlib_inflate.inflate(dB) # Exception thrown
# => Exception: Zlib::NeedDict: need dictionary
zlib_inflate.set_dictionary(A)
zlib_inflate.inflate(dB)
# => "A super string with differences, let's see how much extra space the..."

1 个答案:

答案 0 :(得分:3)

您也可以使用zlib执行此操作。压缩stringB时,使用deflateSetDictionary()函数提供stringA作为字典。另一方面,在解压缩stringB时已经有了stringA,所以在解压缩stringB之前使用inflateSetDictonary()和stringA。

然后

zlib将找到与stringA匹配的stringB部分,并指向stringA中的那些部分。

在压缩stringC时,通过提供stringA和stringB作为字典连接,您可以做得更好。等等。字典最长可达32K字节。