2009年03月02日 09:00 [Edit]
javascript - でデータを圧縮/伸張する
これでもまだ税率が高かったので。
404 Blog Not Found:javascript - Yet Another Base64 transcoderBase64の利点は、なんといっても「固定税率」、それも比較的「税率が低い」ことにあります。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::RawDeflate と IO::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
http://www.tagindex.com/cgi-lib/q4bbs/patio.cgi?mode=view&no=2506
のスレッドにもあるように、使われている deflate.js
何かのデータパターンで正常に圧縮できないようです。
たしかに違和感ありますね。表現を改めました。
Dan the Nullingual
というわけでCESU-8に関する表記を加えました。
Dan the Man with Too Many Encodings to Support
s/一端UTF-8/一旦CESU-8/
ですかね。