【问题标题】:How to compress a string?如何压缩字符串?
【发布时间】:2011-04-08 02:37:09
【问题描述】:

我想对一种字符串进行可逆压缩,这样我就可以将它包含在 URL 中,而无需跟踪它所指的内容。我要压缩的字符串是 SVG 路径字符串,这是一个简短的入门:http://apike.ca/prog_svg_paths.html

基本上,字符串包含一个字符,后跟任意数量的整数,然后是另一个字符,后跟任意数量的整数,依此类推。

如果有人知道这方面的好资源,将不胜感激!

杰森

【问题讨论】:

    标签: javascript compression svg


    【解决方案1】:

    许多压缩算法都有很好的文档记录,有几个甚至有 js 实现:

    • GZip一种常见的(合理的)好的压缩算法,我知道有一个JS impl,我只是在寻找URL

    • LZW另一个问题指向JS中的LZW实现

    • Arithmetic coding(我做了这个,但是它使用的模型很愚蠢,所以没有达到它可以达到的最佳压缩率)

    【讨论】:

    • GZip 链接似乎已损坏:|
    【解决方案2】:

    听起来您可能会从单 RLE 压缩和双 RLE 压缩中受益。

    可以在此处查看有关此内容的入门:

    http://pp19dd.com/2011/10/query-string-limits-encoding-hundreds-of-checkboxes-with-rle/#demo

    该库应该足够灵活,可以将您的压缩模式修改为更可取的东西。文章解释了这是如何工作的;可能是优化 SVG 案例的良好开端。

    【讨论】:

    • RLE 根本无法很好地压缩 SVG 路径数据。
    【解决方案3】:

    以下解决方案返回一个压缩的 Base64 编码字符串。

    使用下面的代码创建一个名为 zip.js 的文件,然后查看下面的用法。

    // Apply LZW-compression to a string and return base64 compressed string.
    export function zip (s) {
      try {
        var dict = {}
        var data = (s + '').split('')
        var out = []
        var currChar
        var phrase = data[0]
        var code = 256
        for (var i = 1; i < data.length; i++) {
          currChar = data[i]
          if (dict[phrase + currChar] != null) {
            phrase += currChar
          } else {
            out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0))
            dict[phrase + currChar] = code
            code++
            phrase = currChar
          }
        }
        out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0))
        for (var j = 0; j < out.length; j++) {
          out[j] = String.fromCharCode(out[j])
        }
        return utoa(out.join(''))
      } catch (e) {
        console.log('Failed to zip string return empty string', e)
        return ''
      }
    }
    
    // Decompress an LZW-encoded base64 string
    export function unzip (base64ZippedString) {
      try {
        var s = atou(base64ZippedString)
        var dict = {}
        var data = (s + '').split('')
        var currChar = data[0]
        var oldPhrase = currChar
        var out = [currChar]
        var code = 256
        var phrase
        for (var i = 1; i < data.length; i++) {
          var currCode = data[i].charCodeAt(0)
          if (currCode < 256) {
            phrase = data[i]
          } else {
            phrase = dict[currCode] ? dict[currCode] : oldPhrase + currChar
          }
          out.push(phrase)
          currChar = phrase.charAt(0)
          dict[code] = oldPhrase + currChar
          code++
          oldPhrase = phrase
        }
        return out.join('')
      } catch (e) {
        console.log('Failed to unzip string return empty string', e)
        return ''
      }
    }
    
    // ucs-2 string to base64 encoded ascii
    function utoa (str) {
      return window.btoa(unescape(encodeURIComponent(str)))
    }
    // base64 encoded ascii to ucs-2 string
    function atou (str) {
      return decodeURIComponent(escape(window.atob(str)))
    }
    

    用法:

    import { zip, unzip } from './zip'
    
    // Zip a string
    const str = 'zip it'
    const base64CompressedString = zip(str)
    
    // Zip an object
    const obj = { a: 123, b: 'zipit' }
    const base64CompressedString = zip(JSON.stringify(obj))
    
    // Unzip the base64 compressed string back to an object.
    const originalObject = JSON.parse(unzip(base64CompressedString))
    

    顺便说一句...如果您担心 escape/unescape 被贬值,请考虑polyfill

    来自here 的LZW 算法和来自here 的base64 编码

    【讨论】:

      【解决方案4】:

      你可以试试Huffman compression。不同字符的数量为 20-30,如果字符串很长,压缩应该是有效的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多