2

我必须压缩一长串字符串。我必须单独压缩它们。每个字符串的长度小于 1000 个字符。然而,许多这些字符串都有一个共同的前缀。因此,我想知道是否可以通过首先压缩公共前缀然后存储压缩器的状态并将其提供字符串的后缀来分摊压缩成本。

如果您对如何在 Python 中完成此任务有任何建议,那就太好了。尽管我在标题中提到了 zlib,但任何其他标准模块也可以使用。在这个应用程序中解压速度并不重要,所以我可以承受解压速度相当慢。

4

1 回答 1

2

zlib的Python 接口相当简陋,并且不提供对zlib 的所有功能的访问。如果您可以构建自己的 zlib 接口,那么您可以做您所要求的,等等。

“以及更多”与您单独压缩非常短的字符串这一事实有关,这从本质上限制了您可以获得多少压缩。由于这些字符串有一些共同的内容,你应该使用deflateSetDictionary()inflateSetDictionary()zlib 的功能可以利用这一事实,并可能显着改善压缩。公共内容可以是您提到的公共前缀,也可以是字符串中其他任何地方的公共内容。您将定义一个固定字典,用于包含在字符串中常见的字节序列的最大 32K 的所有字符串。您会将最常见的序列放在 32K 的末尾,而将不太常见的序列放在前面。如果这些字符串的多个类具有不同的公共序列,您可以根据需要创建一组字典并使用第一次调用返回的字典 idinflate()来选择字典。对于一个或多个字典,您只需要确保相同的字典存储在压缩和解压缩端。

至于存储压缩状态,您可以使用deflateCopy(). 这是在 Python 中与copy()方法一起提供的。我不确定这会给你带来多大的速度优势,尽管对于小字符串。

更新:

从最近添加的评论来看,我相信您的用例是您根据请求将许多字符串中的一些发送给接收者。在这种情况下,可能有一种方法可以使用微不足道的 Python 接口获得更好的压缩。您可以使用flushwith 方法Z_SYNC_FLUSH将到目前为止已压缩的内容强制输出。这将允许您将请求的一系列字符串视为单个压缩流。

该过程将是您使用 启动一个压缩对象compressobj()compress()在该对象上使用请求的第一个字符串,收集该对象的输出(如果有),然后flush(Z_SYNC_FLUSH)对该对象执行 a 操作,收集剩余的输出。compress()将和的组合输出发送flush()到已启动 a 的接收器,decompressobj()然后将其用于decompress()该对象及其发送的内容,这将返回原始字符串。(减压端无需冲洗。)

到目前为止,结果与仅压缩第一个字符串没有太大区别。好的部分是您重复该过程而无需创建新的压缩或解压缩对象。只需将compress()andflush()用于下一个字符串,然后decompress()在另一端获取它。第二个字符串以及所有后续字符串的优点是它们可以使用先前字符串的历史进行压缩。然后你不需要构建或使用任何固定的字典。您可以只使用先前请求的字符串的历史记录来提供良好压缩所需的素材。如果您的字符串平均长度为 1000 字节,那么最终发送的每个字符串都将受益于最近发送的 32 个字符串的历史记录,因为用于压缩的滑动窗口是 32K 长。

完成后,只需关闭对象。

于 2012-07-26T13:44:06.063 回答