Base91 をエンコード・デコードする手順
- テキストを 入力 · テキスト に入力するか貼り付けます。エンコードされた文字列が 出力 · basE91 に表示されます。
- バイナリデータの場合は、変換元 を Hex(16進数) か Base64 にして、その形式で貼り付けます。
- デコードするには、方向の切り替えで basE91 → テキスト をクリックします。入力中の改行は無視されます。アルファベット以外の文字があるとデコードが止まり、その位置が示されます。
- 結果は 出力をコピー または ダウンロード で取り出せます。デコードしたバイナリデータには バイトを保存 を使ってください。
basE91 の仕組み
basE91 は Joachim Henke が公開したものです。Base64 は 6 ビットごとに 1 文字を割り当てます。basE91 では、入力のビットをキューに集めて 13 ビットずつ取り出します。2 文字で表せる値は 91 × 91 = 8281 通りで、13 ビットに必要な 8192 通りより少し多くなります。この余裕は最適化に使われます。次の 13 ビットの値が 88 以下なら、エンコーダーは代わりに 14 ビットを取り出し、それでも 2 文字で書きます。
そのため、出力の長さは内容に左右されます。ランダムなデータでは 14 ビットのグループはまれ(全グループの 1.1% 未満)なので、オーバーヘッドは 16/13、約 23% に近くなります。ゼロのビットが多いデータはさらに詰まります。1000 個のゼロバイトは 1143 文字になり、オーバーヘッドは 14% です。
| 入力 | basE91 | Base64 |
|---|---|---|
test | fPNKd | dGVzdA== |
Hello | >OwJh>A | SGVsbG8= |
Hello World! | >OwJh>Io0Tv!8PE | SGVsbG8gV29ybGQh |
| ゼロバイト 4 つ | AAAAA | AAAAAA== |
| ランダムな 1000 バイト | 約 1230 文字 | 1336 文字 |
可変長のグループには副作用があります。固定のブロックサイズがないため、文字列の途中からデコードしたり、任意の位置で分割したりできません。Base64 なら 4 文字の倍数の位置ならどこでも分割できます。
アルファベットと、それが問題になる場所
basE91 のアルファベットは A–Z、a–z、0–9 と次の 29 文字です。
!#$%&()*+,./:;<=>?@[]^_`{|}~"
空白、'、-、\ は含まれません。空白と ' はシェルや引用符で囲んだ文字列で問題を起こし、\ はほぼどこでもエスケープ文字です。それでも二重引用符は含まれており、<、>、& も同様なので、JSON、HTML、XML の中の basE91 にはエスケープが必要で、そのエスケープが Base64 に対する利点の一部を食いつぶします。最も向いているのは、テキストファイル、シングルクォートで囲んだシェルの引数、バイナリセーフなプロトコルのフィールドなど、印字可能な ASCII なら何でも受け付ける場所です。
Python での basE91 エンコーダー
標準ライブラリに basE91 はありません。Henke のアルゴリズムは短いので、そのまま組み込めます。
ALPHABET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~\"")
def b91encode(data: bytes) -> str:
out, queue, nbits = [], 0, 0
for byte in data:
queue |= byte << nbits
nbits += 8
if nbits > 13:
value = queue & 8191
if value > 88:
queue >>= 13
nbits -= 13
else:
value = queue & 16383
queue >>= 14
nbits -= 14
out += ALPHABET[value % 91], ALPHABET[value // 91]
if nbits:
out.append(ALPHABET[queue % 91])
if nbits > 7 or queue > 90:
out.append(ALPHABET[queue // 91])
return "".join(out)
b91encode(b"test") # 'fPNKd'
どの入力に対しても、このページと同じ出力になります。Python でのバイト列の扱いについては Python のページ をご覧ください。
Base91 を選ぶべきとき
出力の 1 バイト 1 バイトが重要で、通信路が印字可能な ASCII をほぼすべて受け付ける場合に basE91 を選んでください。コンパクトなログや、長さに厳しい上限があるテキストフィールドなどです。JSON、URL、HTML、メールに入れるものなら、Base64 のほうが安全で、長さもほとんど変わりません。固定ブロックで 25% のオーバーヘッドがよければ、PDF と PostScript で標準化されている Ascii85 があります。
よくある質問
Base91 ではどの文字を使いますか?
印字可能な 95 種類の ASCII 文字から、空白、アポストロフィ '、ハイフン -、バックスラッシュ \ を除いたすべてです。残るのは英字、数字、二重引用符を含む 29 個の記号です。
Base91 は Base85 より小さくなりますか?
わずかに小さくなります。ランダムなデータは basE91 で約 23%、Base85 ではちょうど 25% 増えます。ここで試したところ、100,000 バイトのランダムなデータは、Ascii85 の 125,000 文字に対して 122,976 文字になりました。ゼロバイトが長く続くデータでは、オーバーヘッドは約 14% まで下がります。
Base91 があまり普及していないのはなぜですか?
RFC がなく、出力には JSON、シェル、HTML でエスケープが必要な " などの文字が含まれます。さらに可変長のビットグループのせいで、Base64 より遅く実装も難しくなります。数パーセントの節約がそれを上回ることはまれです。
ほかのライブラリが書いた Base91 をデコードできますか?
Henke の basE91 のアルファベットとビット順を使っていればデコードでき、ほとんどのライブラリはそうしています。独自の Base91 アルファベットを持つライブラリも少数あり、その出力はここでエラーなくデコードされますが、誤ったバイト列になります。