デコード・エンコードを深ぼってみる

# はじめに
画像やメールを使うと`Base64でデコードとエンコード`するという場面に出会います。
これまで、ふんわりは理解していましたが、詳細が気になったので調べてみました。

## そもそもBase64とは？
- **データのエンコード方式**で、主に以下の用途で使用されます。
  - 電子メールの添付ファイル
  - Basic認証（HTTPヘッダー）
  - ファイルアップロード
- **全てのデータを64種類の文字（64進数）で表現**します。

## **Base64で使用する64種類の文字**
| 種類      | 使用文字              |
|-----------|-----------------------|
| アルファベット | A～Z, a～z            |
| 数字      | 0～9                  |
| 記号      | `+`, `/`              |
| 補足記号   | `=`（不足部分の埋め合わせ）|

## **Base64が必要な理由**
- 通信や保存の際、一部のシステムでは**ASCII文字（7bit）**しか扱えない制約がある。
例：電子メールでは日本語や画像データを扱えない。

- エンコーディング制限: 一部の通信プロトコルやサービス（例えば、HTTPでのPOSTリクエスト）では、バイナリデータを直接扱うことができず、通常はテキストデータに変換する必要がある。

なので、Base64で**バイナリデータをASCII文字に変換**し、幅広い環境で扱えるようにするわけですね。

ASCIIがいまいち分からない方は、記事の最後に余談で書いてるのでご参照ください〜

---

### **エンコードの手順**
じゃあ、バイナリデータをBase64に変換することをエンコードと呼ぶのは分かったけど、具体的にどういう操作をしているのでしょうか。その手順を追ってみます。

以下は、**画像データをBase64エンコードする例**です。

---

### 画像データをBase64エンコードする手順

1.**画像データ（バイナリ）を読み込む**
    
   - バイナリデータとしては以下のように表現されます:  
     ```
     10001001 01010000 01001110 01000111 00001101 00001010 00011010 00001010
     ```
---
2.**6ビットずつに分割**
   - 上記のバイナリデータを6ビット単位に分割します:  
     ```
     100010 010101 000001 001110 010001 110000 110100 001010 000110 100000 1010
     ```
_
   - 6ビット単位にならない部分は不足分を`0`で埋めます:
     ```
     100010 010101 000001 001110 010001 110000 110100 001010 000110 100000 001010
     ```

---

3.**Base64変換表を使って文字に変換**
   - 分割した6ビットをBase64の文字変換表に基づいて対応する文字に変換します:  
     ```
     100010 -> i  
     010101 -> V  
     000001 -> B  
     001110 -> O  
     010001 -> R  
     110000 -> w  
     110100 -> 0  
     001010 -> K  
     000110 -> G  
     100000 -> g  
     001010 -> K  
     ```
_
   - ここでの出力例:
     ```
     iVBORw0KGg==
     ```

---

4.**不足部分を`=`で埋める**
   - エンコードされた文字列が4の倍数になるように末尾を`=`で埋めます（この例ではすでに4の倍数なので不要）。

---

これで画像データをBase64にエンコードできました🎉

### **デコードの手順**
次に、Base64でエンコードされた文字列を受け取った側が元のバイナリデータに戻すには、デコードと逆の手順で処理すれば良さそうです。

### Base64文字列をデコードする手順

1.**Base64文字列を取得する**
   - エンコードされたBase64文字列を取得します（例: `iVBORw0KGg==`）
---

2.**Base64文字変換表を使ってバイナリに変換する**
   - 各文字を6ビットのバイナリに変換します。  
     Base64文字変換表を参照し、以下のように対応させます。  
     ```
     i -> 100010  
     V -> 010101  
     B -> 000001  
     O -> 001110  
     R -> 010001  
     w -> 110000  
     0 -> 110100  
     K -> 001010  
     G -> 000110  
     g -> 100000  
     K -> 001010  
     ```

---

3.**6ビットを連結する**
   - 6ビット単位のバイナリを全て連結します。  
     ```
     100010 010101 000001 001110 010001 110000 110100 001010 000110 100000 001010
     ```

---

4.**8ビット単位に戻す**
   - 元のデータ形式に戻すため、6ビットごとに連結されたバイナリを8ビット単位に戻します。  
     ```
     10001001 01010000 01001110 01000111 00001101 00001010 00011010 00001010
     ```

---

5.**データを復元する**
   - バイナリデータを元の形式に戻します。これは、画像データや文字列など、元のデータ形式に従って扱われます。

---

## エンコードとデコードの比較
エンコードとデコードの手順は逆の処理を行います。

| 手順            | エンコード                                               | デコード                                               |
|-----------------|---------------------------------------------------------|-------------------------------------------------------|
| 入力            | バイナリデータ                                          | Base64文字列                                          |
| 処理1           | バイナリデータを6ビット単位に分割                       | Base64文字列を6ビット単位のバイナリに変換            |
| 処理2           | Base64変換表を使って文字に変換                          | 6ビットのバイナリを連結し、8ビット単位に分割         |
| 処理3           | 4の倍数になるように末尾を`=`で埋める（必要な場合のみ） | 元のバイナリデータを復元                              |
| 出力            | Base64文字列                                            | 元のデータ（バイナリ、画像、文字列など）             |

---

### **デコードの注意点**
- `=`の末尾は**パディング**として使われるので無視してデコードする
- 変換後のデータは、**元のデータ形式（画像、テキストなど）に従って復元**する必要がある


# まとめ
調べてみると、意外と単純でしたが勉強になりました。
「単純にバイナリで送ればいいじゃん」って思いそうですが、そうできない場面もあるのでそんな時はエンコードして使えるようにしましょう、ということですね🤔

# ASCIIとは（余談）

#### 1. **ASCIIの基本**
- ASCIIは、**7ビットの文字コード**で、以下を表すのに使われます：
  - アルファベット（大文字・小文字）
  - 数字
  - 一部の記号（例: `!`, `@`, `#` など）
  - 制御文字（例: 改行 `LF`、タブ `TAB`）

---

#### 2. **ASCIIコード表**
ASCIIコード表は縦軸と横軸で構成され、**7ビット（128文字）** で表されます。表の使い方としては、縦軸と横軸の値を組み合わせて1文字を特定します。たとえば：
- `A` のコードは **0x41**（16進数）、**01000001**（2進数）
- `a` のコードは **0x61**（16進数）、**01100001**（2進数）


![ASCIIコード表](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3960433/fd180acd-e47c-c80e-ecfa-4ae947fe2e0f.png)

---

#### 3. **先頭ビットとパリティ**
- これは一部の古い通信方式で使用される概念です。**パリティビット**はデータ通信時にエラーを検出するために追加されるもので、7ビットのASCIIに1ビットを加えて8ビットで送信していました。

- 現在では、パリティビットを使用しないケースが多く、ASCIIは純粋に7ビットの文字コードとして解釈されます。

---

#### 4. **補足: ASCIIの限界**
ASCIIは**英語圏を想定**して作られた文字コードなので、**日本語や多言語**には対応していません。そのため、国際化のためには拡張された文字コード（UTF-8やUnicode）が必要です。

---