【问题标题】:Is there a way to compress a string into a smaller string with reversibility?有没有办法将字符串压缩成具有可逆性的较小字符串?
【发布时间】:2019-05-24 09:28:49
【问题描述】:

我正在尝试通过铱星网络传输字符串,发送数据的成本非常高。我想知道是否有办法压缩大字符串,例如: {"packet":01,"reporting time":1500, "altitude":6500,"latitude":0,"longitude": 0,"ballast":34,"parachute":0}

变成一个更小的字符串,例如: f5fk43d2 .该过程必须是可逆的,以便可以在另一端解码和读取数据。这可能吗,如果可以,我该怎么做。

我已经尝试过 j.w.r 的这个答案:Shortening a string in Java,但它似乎是不可逆转的。它确实将一个大字符串转换为一个较小的字符串。

该过程必须产生一个小于原始字符串的字符串。

感谢任何帮助!

【问题讨论】:

  • 您可以查看一个常见的压缩方案,例如 deflate(用于 .zip 文件),它在 Java 的标准库 (Deflater) 中有一个实现
  • 你有没有考虑过使用MessagePack之类的东西?或者只是简单地通过 zip 压缩压缩文本并将其转换为 base64?
  • CBOR 可能是一个选项。如果您不想发送二进制文件,则使用 base64
  • 如果引号中的部分可能取值的数量有限,并且还知道每个冒号后面的部分是一定范围内的数字;那么你可以利用它用更短的字符串来表达它。

标签: java encoding compression transmission


【解决方案1】:

让我们从您的示例开始,作为对您模糊“小得多”的描述。您将 107 个字符(856 位)压缩为 8 个字母数字字符,无论如何,每个字符似乎都被限制为 36 种可能性。我会很慷慨,并假设也允许使用大写字母,可能还有两个标点符号作为香料,最多可以使用 64 个字符。所以这是每个字符 6 位乘以 8 个字符,即 48 位。这是 18 倍压缩系数。不,你不会无损地得到那个,至少在示例中没有证明的数据中没有大量冗余。我将再次慷慨并假设被压缩的消息限制为 96 个可能的 ASCII 字符(例如,删除 127 并包括新行)。然后消息为 705 位,压缩系数几乎为 15 以达到 48 位。仍然没有发生。

无损压缩来自统计偏差和冗余。统计偏差是某些符号相对于其他符号的普遍性,冗余是数据中的重复模式,例如在您的示例中重复子字符串,例如“itude”和“500”。要获得良好的压缩,您需要利用这些东西,并且需要大量数据才能利用它们。如果孤立地考虑,像您的示例这样的短字符串几乎不会压缩或通常根本不压缩。

您可以尝试在另一端维护一个压缩上下文和相关的解压缩上下文,通过它们您可以按照定义明确的顺序发送一系列消息。 IE。它们需要以与压缩相同的顺序进行解压缩。然后,您将能够利用许多消息的冗余和偏差,并可能获得一些不错的压缩。如果这些相同的 JSON 属性不断重新出现,而且更好的是,如果它们经常具有相同的值,那么您可以获得显着的压缩。

例如 zlib 的刷新操作将允许发送到目前为止压缩的数据,以避免压缩器在构建块时引入的延迟。如果可能,您会希望避免刷新,因为它们会减少压缩。因此,您可以有一个时间限制,即在清除最后一条要发送的消息之前,您愿意等待另一条消息传输多长时间。

【讨论】:

    【解决方案2】:

    考虑尝试将某个 X 字符字符串转换为 Y 字符字符串的数学运算,例如 X > Y(即您正在尝试缩短字符串的长度)。

    那么,假设字符串是字母数字的;这给了我们 26 个可能的小写字母、26 个可能的大写字母和 10 个我们可以使用的可能数字(即 62 种可能性)。这意味着对于一个 X 字符的字符串,我们将有 62^X 个可能的字符串,而对于一个 Y 字符的字符串,我们将有 62^Y 个可能的字符串。

    现在,考虑我们是否尝试将所有 X 字符串映射到 Y 字符串。让我们让函数 f(S) 将字符串 S(一个 X 字符串)映射到一个 Y 字符串。然后,因为 X > Y,我们必须将一些 X 字符串映射到一些相同的 Y 字符串。考虑以下简单示例:

    X = 3。Y = 2。 然后,我们有 62^3 个可能的 3 字符字符串 (238,000) 和 62^2 (3800) 个可能的 Y 字符字符串。然后,我们有 234,000 个 3 字符的字符串比 2 字符的字符串。

    现在,假设我们尝试使用某个函数 f(S),我们尝试将每个 3 个字符的字符串转换为 2 个字符的字符串。那么,当我们试图将 2 字符的字符串转换回 3 字符的字符串时,自然会遇到问题,因为这意味着 f(S) 必须将一些 3 字符的字符串转换为相同的字符串(所以我们不能不知道映射回哪一个!)。这是因为 2 字符字符串的域小于 3 字符字符串的域(并且发生是因为 f(S) 不能单射,这意味着没有有效的逆)。

    因此,没有足够的 2 个字符的字符串可能映射回每个 3 个字符的字符串,您会发现这可以推广到所有 X > Y。

    您可以限制较大字符串域中的某些字符,但正如您所说的问题,这是不可能的。

    编辑,因为我觉得我应该提到这一点:有一些算法用于将较少字符的字符串压缩为包含较多字符的较小字符串。话虽如此,我建议看看这个: An efficient compression algorithm for short text strings

    【讨论】:

    • 您是否与 Smaz 合作过,在您链接的答案中引用?
    【解决方案3】:

    首先,希望很清楚,不存在任何无损压缩算法可以采用长度为 n 的任意字符串并始终将其压缩为唯一的较短字符串。这是一个数学事实。

    话虽如此,有一些流行的算法运行良好:

    Huffman encoding: 相当适合初学者并且可以自己实现。基本思想是将更常见的字符映射到较短的二进制字符串,将不太常见的字符映射到较长的二进制字符串,然后将其与告诉您如何解码结果位串的映射打包。缺点是需要额外的空间来存储解码指令

    Lempel-Ziv:我自己从来没有实现过这个,但它是我们今天知道的许多常见文件格式的基础,比如 GIF。那里应该有图书馆。

    【讨论】:

    • 首先,希望很清楚,不存在任何无损压缩算法可以采用长度为 n 的任意字符串并始终将其压缩为唯一的较短字符串。这是一个数学事实。 - 有大量无损压缩方法。它们只是在可以删除的字符数量上更少有效。
    • @Jai 当然这是一个数学事实。压缩算法依赖于某些字符串比其他字符串更常见。它们使“常见”字符串更短,但使不太常见的字符串更长。绝对没有可逆算法可以使每个可能的字符串更短。如果有的话,你可以简单地一遍又一遍地应用它,直到字符串变成一个比特,然后神奇地将 0 或 1 转换为莎士比亚的完整作品。
    • @Jai 是的,但没有“完美”的无损压缩方法。要看到这一点,请取一个长度为 n 的位串。有 2^n 个这样的可能字符串。有 2^(n-1) + 2^(n-2) + ... + 2^0 个可能的字符串比这短。总和为 2^n - 1 个字符串,因此根据 piegonhole 原则,要么两个字符串具有相同的压缩形式(呃——这与哈希冲突的想法相同)——或者某个压缩形式是 longer 比原始字符串,如果您的原始字符串很短并且由许多唯一字符组成,则在存储地图时很容易在 Huffman 编码中发生这种情况。
    猜你喜欢
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 2017-08-18
    • 1970-01-01
    • 2020-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多