この記事で扱うBase64は
RFC 4648 – The Base16, Base32, and Base64 Data Encodings#section-4
で定義されている素朴なBase64です。URLセーフなものであったり、固定長で区切られたりするBase64は取り扱いません。
Base64はオクテットデータ(8bit単位のデータのこと。現代では1byteと同義)を限られた表現空間で自由に表すために生まれた形式です。Base64形式による変換をオクテットデータに実行することで、英数字とほんの少しの記号しか使えないかつての電子メールの様な表現空間で、画像、音楽といったそのままでは表せないデータを表せるようになります。Base64は次の64文字とパディング1文字で自由にバイナリを表します。
Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y
RFC 4648 – The Base16, Base32, and Base64 Data Encodings#section-4
6bit分のバイナリパターン2^6=64種それぞれに英数字と記号を割り振ることによって、英数字と記号のみで自由にデータを表します。64文字を使うからBase”64″なわけですね。
アルファベットの大文字26文字、小文字26文字、数字10文字、記号2文字の合わせて64文字が0個以上連なった文字列が主なデータ部になります。これは[0-9a-zA-Z+/]*で正規表現として記述できます。これの64文字を4文字ずつ使い6*4=24bit、つまり3byteずつデータを表現するのが基本です。例えば次の様になります。
8bit単位のデータを用意
01010111 00100101 11011101 01101100 01011100 01101010
↓6bitずつで区切る
010101 110010 010111 011101 011011 000101 110001 101010
↓10進数に変換
25 62 27 35 33 5 61 52
↓対応する文字に変換
Z + b j h F 9 0
↓24bitを表す4文字ずつにまとめる
Z+bj hF90
変換過程は人間の目で整理できるように示してあります。実際はbitのまま取り扱うので実装したコードはけっこうシンプルです。
24bitずつ8bit単位のデータを区切っているので余りが生まれます。この余りを処理するために、65文字目である=が変換後の文字列末尾に足される時があります。この=の付け足しは={0,2}で正規表現として表せます。4文字ずつ文字列を作るのに、末尾の=の数が0,1,2の3種類に限られるのは8bit単位のデータを24bitずつ文字列まとめているからです。余りなし、8bit余り、16bit余りの3種類しかないわけですね。余り0のパターンは最初の例です。余り8bitのパターンを例にすると次の様になります。
24bitずつ区切った時8bit余る8bit単位のデータを用意
01010111 00100101 11011101 01101100
↓6bitずつで区切る
010101 110010 010111 011101 011011 00
↓6bitずつで区切った時点で余っている2bitを6bitになる様4個の0で埋める
010101 110010 010111 011101 011011 000000
↓10進数に変換
25 62 27 35 33 0
↓対応する文字に変換
Z + b j h A
↓24bitを表す4文字ずつにまとめる
Z+bj hA
↓24bitを表す4文字ずつにまとめた時余っている2文字が4文字になる様に=で埋める
Z+bj hA==
余り16bitのパターンを例にすると次の様になります。
24bitずつ区切った時16bit余る8bit単位のデータを用意
01010111 00100101 11011101 01101100 01011100
↓6bitずつで区切る
010101 110010 010111 011101 011011 000101 1100
↓6bitずつで区切った時点で余っている4bitを6bitになる様2個の0で埋める
010101 110010 010111 011101 011011 000101 110000
↓10進数に変換
25 62 27 35 33 5 48
↓対応する文字に変換
Z + b j h F w
↓24bitを表す4文字ずつにまとめる
Z+bj hFw
↓24bitを表す4文字ずつにまとめた時余っている3文字が4文字になる様に=で埋める
Z+bj hFw=
文字列からオクテットデータの変換は逆方向に行うだけです。デコードも三種類のパターンがあるわけですね。
どの様な8bit単位のデータでも64種の文字の連なりと1種の文字の付け足しで表せることとその変換方法がわかりました。次の正規表現はBase64形式を表現する正規表現です。
[0-9a-zA-Z+/]*={0,2}