Base64 エンコード後の長さ計算
Base64 エンコード後の長さ計算
このレッスンで分かること
- 3 バイト (24bit) を 6bit × 4 文字に分割し、6bit ごとに変換表で対応する文字に置き換えるのが基本動作です
- メールや HTTP のヘッダ、
data:URL、JSON Web Token (JWT) など、テキストしか乗せられない場所にバイナリを埋め込みたい場面は多いですBase64は 8bit のバイト列を、A-Za-z0-9+/の 64 種類の印字可能文字に変換する符号化方式です
Base64 エンコード後の長さ計算 とは
バイト列を Base64 エンコードしたときの文字数を、入力長から数式で求める関数を作ります。本レッスンでは、Base64 エンコード後の長さ計算 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
メールや HTTP のヘッダ、data: URL、JSON Web Token (JWT) など、テキストしか乗せられない場所にバイナリを埋め込みたい場面は多いです。そのとき広く使われている符号化方式が Base64 です。本レッスンではエンコード後の文字数を「入力バイト数」から計算する公式を学び、その公式をコードに落とします。
Base64 とは何か
Base64 は 8bit のバイト列を、A-Z a-z 0-9 + / の 64 種類の印字可能文字に変換する符号化方式です。バイナリを「テキストとして安全に運ぶ」ためのラッパーで、画像 を HTML に埋め込んだり、暗号鍵 を JSON に入れたりする用途で使われます。SMTP や昔の MIME メールでは 7bit のテキストしか送れなかったため、添付ファイルを Base64 で包む文化が定着しました。
Base64 は 暗号化ではなく符号化 です。デコードすれば誰でも元のバイト列に戻せます。秘密にしたい情報は別途暗号化が必要です。
3 バイト (24bit) を 6bit × 4 文字に分割し、6bit ごとに変換表で対応する文字に置き換えるのが基本動作です。O(n) で線形に処理できる単純な変換で、追加のメモリも O(n) 程度しか必要としません。
変換表は仕様で固定されており、6bit の値 0 が A、1 が B、…、63 が / に対応します。だれが書いても同じ出力になるので、MD5 や SHA-256 のハッシュ値を Base64 で表すといった用途にも向いています。
長さの公式
入力が n バイトのとき、出力の文字数は次の式で求まります。
length = ceil(n / 3) * 4
つまり 3 バイトごとに 4 文字を出力し、3 で割り切れない分は 4 文字単位に切り上げます。切り上げた分は末尾の = 文字 (パディング) で埋められます。具体例で確かめます。
n = 0のとき出力は0n = 1のとき出力は4(例:"A"→"QQ==")n = 2のとき出力は4(例:"AB"→"QUI=")n = 3のとき出力は4(例:"ABC"→"QUJD")n = 10のとき出力は16n = 100のとき出力は136
ceil(n / 3)の代わりに(n + 2) / 3を整数除算しても同じ値になります。割り算の繰り上げは整数演算の典型テクニックです。
なぜ (n + 2) / 3 が切り上げになるのかは、紙に書いて 3 つだけ計算すれば腑に落ちます。n = 3k のときは (3k+2)/3 = k、n = 3k+1 のときは (3k+3)/3 = k+1、n = 3k+2 のときは (3k+4)/3 = k+1 になります。割り算が「ぴったり」のときは商そのまま、半端があると +1 切り上げ、というのが整数除算による ceil の正体です。
計算手順
ここでは (n + 2) // 3 * 4 という形でコードに落とします。// は Python の整数除算で、JavaScript なら Math.floor か | 0 で代用します。
Python
def base64Length(n):
return ((n + 2) // 3) * 4上の関数は 3 行ですが、内部で 3 バイト単位への切り上げと 4 倍を一度に行っています。n が 0 のときも ((0+2)//3)*4 = 0 となり、ちゃんと 0 を返します。
JavaScript
function base64Length(n) {
return Math.ceil(n / 3) * 4;
}こちらは Math.ceil で書いた版です。整数演算の (n+2)/3 と結果は同じですが、Math.ceil のほうが「公式そのまま」で読みやすい場合があります。Math.ceil は常に整数値を返すため、追加の変換は不要です。
なぜ 4/3 倍に増えるのか
Base64 は 6bit を 1 文字に割り当てるので、8bit × 3 = 24bit を 6bit × 4 = 24bit にちょうど詰め直します。情報量は同じですが「1 文字あたりの密度」が下がるため、サイズは約 33% 増える と覚えておくと容量見積もりに便利です。
画像を
data:URL に埋め込むと、もとのファイルより 33% 程度大きくなります。これは Base64 のオーバーヘッドです。
例えば 300KB の PNG を data:image/png;base64,... で HTML に埋め込むと、HTML 上では約 400KB を占有します。HTTP/2 以降では小さなアイコンを Base64 で埋め込むより、別ファイルにして並列ダウンロードするほうが速いケースが多いです。容量と性能の両面で Base64 のオーバーヘッドを意識しておく価値があります。
よくある間違い
ceilを忘れてn / 3 * 4と書くと、半端なバイト数 (1, 2, 4, 5...) で結果が小さくなります- パディング (
=) を別途加算してしまい、二重に数えてしまう - 入力に文字列を受け取った場合、
lengthがバイト数か文字数かを混同する (UTF-8 ではあは 3 バイト) - 負の数を渡されても 0 を返すべきところ、
-4のような値が出る URL-safe Base64(+を-に、/を_に置き換える派生形) と通常の Base64 を取り違える
やってみよう
関数 base64Length(n) を実装してください。n は 0 以上の整数で、Base64 エンコード後の文字数 (パディング込み) を返します。n = 0 のときは 0 を返します。引数が負数のときも 0 を返す安全策を入れておくと、呼び出し側がうっかり負数を渡したときにも 落ち ません。
よくある質問
Q. 進数変換はなぜプログラミングで必要なのですか?
A. コンピュータは内部で 2 進数を扱うため、ビット演算やメモリ操作で 2 進・16 進の理解が必須です。色コード(#FF8800)、ファイル権限(0755)、IP アドレスのサブネット計算など、実務でも進数変換に触れる機会は多くあります。
Q. 10 進数を 2 進数に変換するアルゴリズムは?
A. 数を 2 で割り続け、余りを下から並べると 2 進表現になります。例えば 13 → 6 余 1 → 3 余 0 → 1 余 1 → 0 余 1 で 1101 です。多くの言語は bin() / Integer.toBinaryString() などの組み込みがあるため、それを使うのが安全です。
Q. Base64 はなぜ 4/3 倍に膨らむのですか?
A. 3 バイト(24 ビット)を 4 文字(各 6 ビット)に変換するため、データ量が 4/3 倍になります。8 ビット境界の任意バイト列を ASCII 印字可能文字だけで安全に運ぶための仕組みで、メール添付や URL 内のバイナリ埋め込みで使われます。
次のレッスン
次は URL エンコード対象文字数 に進みましょう。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- Base64 の長さ の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. Base64 の長さ とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 公式 ceil(n / 3) * 4 で文字数を求める
- n=0 のときは 0 を返す
- 戻り値は整数 (Base64 文字数) で、パディング = も含めた長さを表す
入出力例
test-cases.txt
base64Length(0) → 0
base64Length(1) → 4
base64Length(2) → 4
base64Length(3) → 4
base64Length(4) → 8
base64Length(10) → 16
base64Length(100) → 136
base64Length(999) → 1332