【问题标题】:Compress a short but repeating string压缩一个短但重复的字符串
【发布时间】:2012-06-12 09:07:20
【问题描述】:

我正在开发一个需要在查询字符串(特别是 GET 而不是 POST)上获取文件列表的网络应用程序,例如:

http://site.com/app?things=/stuff/things/item123,/stuff/things/item456,/stuff/things/item789

我想缩短那个字符串:

http://site.com/app?things=somekindofencoding

字符串不是很长,从 20 到 150 个字符不等。这么短的东西并不适合 GZip,但它确实有很多重复,所以压缩应该是可能的。

我不想要字符串的数据库或字典 - URL 将由与使用它的应用程序不同的应用程序构建。我想要一个可缩短此 URL 的可逆压缩。它不需要是安全的。

是否有现有的方法可以做到这一点?我在 C#/.Net 中工作,但很乐意从其他语言/堆栈中调整算法。

【问题讨论】:

  • /stuff/things/item* 总是一样吗?如果是,你为什么不简单地传递123,456,789
  • 对数据有什么限制?它们可以用 (e)BNF 表示吗?即数据格式是否规则?
  • @SteveB 并非总是如此,但一个电话可能很多 /stuff/things/item 和另一个 /files/item/items/thing 或其他。
  • 如果你事先知道参数的种类,你可以使用类似:http://site.com/app?things=123,456,789&files=ABC,DEF 实际上,你应该描述url包含什么样的数据。
  • @RuneFS 数据大致是文件名,所以`a-zA-Z0-9_-,.~/`

标签: c# .net compression


【解决方案1】:

如果您可以在 BNF 中表达数据,您可以为数据构建解析器。您可以发送 AST,而不是发送数据,其中每个节点将被标识为一个字符(或者如果您有很多不同的节点,则为多个字符)。在你的例子中

我们可以有

files : file files
      | 
file : path id
path : itemsthing
     | filesitem
     | stuffthingsitem

您可以将文件列表表示为 path[id1,id2,...,idn] 使用 0,1,2 作为路径,输入为:

/stuff/things/item123,/stuff/things/item456,/stuff/things/item789
/files/item1,/files/item46,/files/item7

然后你会得到?things=2[123,456,789]1[1,46,7]

其中/stuff/things/item2 表示,/files/item/1 表示[...] 中的每个数字都是一个ID。所以2[123] 会扩展为/stuff/things/item123

编辑方法不必是静态的。如果您必须动态发现重复的项目,您可以使用相同的方法并在标识符和令牌之间传递映射。在这种情况下,上面的示例将是

?things=2[123,456,789]1[1,46,7]&tokens=2=/stuff/things/,1=/files/item

如果语法这么简单当然会更好

?things=/stuff/things/[123,456,789]/files/item[1,46,7]

使用如此短的字符串将重复部分压缩到小于唯一值是可能的,但很可能必须基于限制可能的值或在“压缩”时实际增加大小的风险

【讨论】:

  • 好吧,这看起来很有希望,但感觉就像重新发明轮子从头开始编写类似的东西。我也不(提前)确切地知道字符串的重复部分是什么,所以我也需要动态地弄清楚这一点。有没有什么东西可以做到这一点?
  • 因为它只是一个键值映射,你可以争辩说没有实现(键值映射),同时争辩说该方法的简单性将保证框架解决方案毕竟它更少比说 200 LOC
  • 如果我知道将要传递的模式,你的方法是完美的,但不幸的是我不能确定 - 它可能会得到类似 /stuff/things/X,item/stuff/Y,things/item/1 的东西。我正在寻找可以从该模式中识别出“stuff”、“thing”、“item”重复并且可以替换的东西。
  • 您的编辑很有道理,但我不确定如何应用它。我需要快速弄清楚重复模式是什么并将它们标记化(“stuff”、“thing”、“item”只是我虚构的例子)。所以/stuff/things/X,item/stuff/Y,things/item/1 会变成:/#a/#b/X,#c/#a/Y,#b/#c/1|1=stuff2=things3=item(不幸的是更长:-S)。
  • @Keith 您可以将其压缩为 '/12[X]31[Y]23[1]1stuff2things3item' 长度为 34 个字符或小于原始字符的 5/6(约定为每个以 / 结尾的术语,否则长度将为 37,这将是原始术语的 6/7)。如果所有术语都少于三个字符并且只使用一次,那么组织会更短,但对于任何压缩算法,都会有那些产生更大输出的输入
【解决方案2】:

您可以尝试zlib 使用原始 deflate(没有 zlib 或 gzip 标头和预告片)。即使在由可打印字符组成的短字符串上,它通常也会提供一些压缩,并且会寻找并利用重复的字符串。我没试过,但也可以看看smaz 是否适用于您的数据。

我建议获取大量真实示例 URL,用于对可能的压缩方法进行基准测试。

【讨论】:

    猜你喜欢
    • 2019-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多