2009年03月02日 09:00 [Edit]

javascript - でデータを圧縮/伸張する

これでもまだ税率が高かったので。

404 Blog Not Found:javascript - Yet Another Base64 transcoder
Base64の利点は、なんといっても「固定税率」、それも比較的「税率が低い」ことにあります。Paddingなしなら、3バイトが4バイトにencodeされるので、33%ということになります。これに対してencodeURIComponentの税率は、UTF-8基準で最高で3倍、UTF-16基準で最高で4.5倍にも達します。

ついに負の税率、すなわち税還付を実現しました!


まずはデモを。

Inflated + Base64-Decoded (Original):
chars / bytes
Deflated + Base64-Encoded (Compressed):
bytes

その仕組みですが、圧縮時にはいったんUTF-8のバイト列にしたもの(CESU-8)をRFC1951の Raw Deflate にかけた上で Base64 encode し、伸張時には逆に Base 64 decode したものを Raw Inflate し、それを(UTF-16である) JavaScript String にしているというわけです。

Raw Deflate のエンジン部分は、「高度な JavaScript 技集」の inflate.js および deflate.js から拝借させていただきました。私が直したところは、グローバル変数(関数だけだがそれも含む)をローカルに閉じ込めたこと、そしてIEでも「使える」速度で動くよう、String の+演算を減らしたことぐらいでしょうか。10年も前にあれほど高度な JavaScript が書かれたことが驚きです。Masanao Izumo 様、ありがとうございました。

と同時に、「404 Blog Not Found:javascript - Yet Another Base64 transcoder」で発表し、drryさんがばっさり手直ししてくれた base64.js を再びばっさり手直ししました。最初のバージョンでは 文字列をちまちまいじっていましたが、drryさんがそれを一端配列に直してから操作し、そして文字列に戻すよう書き換えたのですが、これだと(特に string + string が遅いIEで)高速になりはするのですが、メモリーの使い方が富豪すぎて、大きなデータだとブラクラになっちゃったのです。

結局どうやったかというと、正規表現を使いました。これなら文字列から文字列への変換なので、文字を一つ一つ配列に入れてから処理するよりメモリーも食いませんし、より高速でもあります。実際jQueryとPrototype.js、そして本blogのHTMLなどを食わせてみましたが、IE7でもぼちぼち動きますし、Chromeに至ってはとてもJSで書かれたとは思えないほどさくさく動きました。これなら充分実用になるのではないでしょうか。

なお、サーバー側で Raw Deflate/Inflate する方法なのですが、Perlであれば IO::Compress::Zlib をインストールしておけば、 IO::Compress::RawDeflateIO::Uncompress::RawInflate がもれなく付いてくるので、それを使えばよいでしょう。以下、コマンドラインで指定したファイルを Raw Deflate した上で Base64 encode する perl script の例です。

#!/usr/local/bin/perl
use strict;
use warnings;
use IO::Compress::RawDeflate ':all';
use MIME::Base64;


sub slurp{
    my $filename = shift;
    open my $fh, '<', $filename or die "$filename:$!";
    local $/;
    my $content = <$fh>;
    close $fh or warn "$filename:$!";
    return $content;
}

my $orig = slurp shift || die "$0 file";
my $deflated;
rawdeflate(\$orig => \$deflated) or die "deflate failed: $RawDeflateError";
print encode_base64($deflated);

Enjoy!

Dan the Inflated JavaScripter

追記:IPhoneでも動いた!


この記事へのトラックバックURL

この記事へのトラックバック
ついムラムラと。 /lang/javascript/math-bigint/trunk - CodeRepos::Share - Trac dankogai's js-math-bigint at master - GitHub フルスクラッチでないのでかえって苦労したかも。
javascript - Math.BigInt で多倍長整数演算【404 Blog Not Found】at 2010年09月12日 03:16
費用をかけずにウェブページを最適化 Googleウェブサイトオプティマイザー活用術 Aptanaで始めるJavaScriptライブラリ「jQuery」超入門 ...
[TODAY's TOPIC] March 3, 2009【Movable Type 備忘録】at 2009年03月03日 21:36
この記事へのコメント
具体的に、どこがおかしいのかは僕にはわかっていないのですが、
http://www.tagindex.com/cgi-lib/q4bbs/patio.cgi?mode=view&no=2506
のスレッドにもあるように、使われている deflate.js
何かのデータパターンで正常に圧縮できないようです。
Posted by yukobayashi at 2010年12月24日 17:38
m11mさん、
たしかに違和感ありますね。表現を改めました。
Dan the Nullingual
Posted by at 2009年03月02日 19:44
「賞賛の名に値します」っておかしくないですか。
Posted by m11m at 2009年03月02日 16:59
kariya_mitsuruさん、
というわけでCESU-8に関する表記を加えました。
Dan the Man with Too Many Encodings to Support
Posted by at 2009年03月02日 16:08
重箱の隅ですが、
s/一端UTF-8/一旦CESU-8/
ですかね。
Posted by kariya_mitsuru at 2009年03月02日 12:52