復活の呪文とは
データを64種類のひらがなから成る文字列に変換し、紙などに記録する保存方式である。主に記録用電子媒体が存在しない環境で用いられた。
使用する文字
ぴったり64種類1なので、6ビットの情報を表現できる。
あいうえお まみむめも やゆ
かきくけこ らりるれろ よわ
さしすせそ がぎぐげご
たちつてと ざじずぜぞ
なにぬねの ばびぶべぼ
はひふへほ ぱぴぷぺぽ
変換形式
- 元データを6ビットずつに分割(6ビットに満たない分は0を追加して6ビットにする)
- 変換表を使って各6ビットの値を変換
↓これが
abc
↓こうなって
01100001 01100010 01100011
011000 010110 001001 100011
↓こうなる
のぬこら
って、これまんまBase64じゃん
Base64は、データを64種類の印字可能な英数字のみを用いて、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのエンコード方式である。
単なる偶然ではなさそうですね?2
実装してみる
使用する文字
理解も兼ねてクラス化してみた。復活エンコーダー。
class FukkatsuEncoder:
__USABLE_CHARS = \
'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほ' \
'まみむめもらりるれろがぎぐげござじずぜぞばびぶべぼぱぴぷぺぽ' \
'やゆよわ'
復活の呪文に変換する
内部で2進数を表現する「文字列」に変換しているので、わかりやすい代わりに効率は悪い。
def encode(self, raw: bytes) -> str:
b = ''.join(map(lambda c: format(c, '08b'), raw))
# 6の倍数になるようゼロ埋めする
b += '00000'
b = b[0:-(len(b)%6)]
# 連番が偶数となる要素は空文字なので除外する
encoded = ''.join(map(lambda c: self.__USABLE_CHARS[int(c, 2)], \
re.split('(.{6})', b)[1::2] \
))
return encoded
復活の呪文から元データを復元する
なんか動かない
def decode(self, encoded: str) -> bytes:
b = ''.join(map(lambda c: format(self.__USABLE_CHARS.find(c), '06b'), \
encoded))
# 8の倍数に満たない場合、末尾は捨てられてしまうので問題なし
raw = ''.join(map(lambda i: chr(int(i, 2)), \
re.split('(.{8})', b)[1::2]))
return raw
decode()
の引数に「あいう」を渡すと以下のエラー。
UnicodeEncodeError: 'cp932' codec can't encode character '\xe3' in position 0: illegal multibyte sequence
文字列とバイト列は別物
バイトを文字に変換chr()
してから結合join()
しているので、マルチバイト文字の場合がダメでした。ここはバイト列bytes()
を作ってから、必要に応じて文字列に変換するのが正解。
raw = bytes(map(lambda i: int(i, 2), \
re.split('(.{8})', b)[1::2]))
ソースコード
Gistに置いておきました。decode()
のバグっていたリビジョンも残してあります。
https://gist.github.com/cress-cc/985dc5923686e21f19ee14a57129ade4
これは何の役に立つのか
何の役にも立ちません。
-
一般人には伝わらない感覚 ↩