web-dev-qa-db-ja.com

文字列を圧縮する方法は?

文字列の種類を可逆的に圧縮して、参照先を追跡せずにURLに含めることができるようにしたいと思います。圧縮したい文字列はSVGパス文字列です。ここに短い入門書があります: http://apike.ca/prog_svg_paths.html

基本的に、文字列には文字が含まれ、その後に任意の数の整数が続き、次に別の文字の後に任意の数の整数が続きます。

誰かがこれのための良いリソースを知っているなら、それは大いにありがたいです!

ジェイソン

18
FurtiveFelon

多くの圧縮アルゴリズムは十分に文書化されており、いくつかはjs実装さえ持っています:

  • GZip 一般的な(合理的に)優れた圧縮アルゴリズムです。JSimplがあることはわかっています。URLを探しているだけです。

  • [〜#〜] lzw [〜#〜] 別の質問はJSでのLZW実装を指しています

  • 算術符号化 (私はこれを行いましたが、使用するモデルは愚かであるため、最高の圧縮率を達成できません)

6
olliej

シングルおよびダブルRLE圧縮の恩恵を受ける可能性があるようです。

これに関する入門書はここで見ることができます:

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

ライブラリは、圧縮パターンをより好ましいものに変更するのに十分な柔軟性を備えている必要があります。この記事では、これがどのように機能するかを説明しています。 SVGケースを最適化するための良いスタートかもしれません。

3
pp19dd

ハフマン圧縮 を試すことができます。異なる文字の数は20〜30であり、文字列が長い場合は、圧縮が効果的です。

1
pepkin88

次のソリューションは、圧縮された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))

ところで...エスケープ/アンエスケープが減価償却されることを懸念している場合は、 polyfill を検討してください

ここ からのLZWアルゴリズムと ここ からのbase64エンコーディング

0
Simon Hutchison