プログラマのための文字コードガイド：SHIFT_JISからUTF-32、サロゲートペアまで

:man_tone1: これは **SHIFT_JIS** (ゴト
:man_tone1: これは **SHIFT_JIS-2004** (ゴト
:man_tone1: これは **Windows-31J** (ゴト

:person_with_blond_hair_tone1: 全部同じじゃないですか!?

:man_tone1: これだから素人はダメだ!もっとよく見ろ!

# 文字コードの歴史と特徴
文字コードには様々なエンコード方式があります。
本記事では、SHIFT_JIS、SJIS、Windows-31J、cp932、EUC-JP、UTF-8、UTF-16、UTF-32について、それぞれの歴史と特徴を紹介します。
また、サロゲートペアと絵文字についても触れます。

## SHIFT_JIS (SJIS)
※Rubyでは SHIFT_JIS ≠ SJIS なので注意。(1.9.3以降SJISはWindows-31Jのエイリアスになっています)

https://github.com/ruby/ruby/blob/40251ed0dfe99bb09c2fa542fce603ade25e3729/enc/windows_31j.c#L69

### 歴史
SHIFT_JISは、1980年代に日本のパソコンで広く使われるようになった文字コードで、ASCII、JIS X 0201およびJIS X 0208を基にして開発されました。

### 特徴
- **1バイトと2バイトの組み合わせ**: ASCII文字は1バイトで表現され、日本語の漢字やかなは2バイトで表現されます
- **広い互換性**: 当時の日本のパソコンや携帯電話で広く使用されました
- **エンコード範囲**: 2バイトコードの範囲が広く、誤ったバイトシーケンスが発生しやすいため、データの整合性に注意が必要です。また、Shift_JISは互換性が高いものの、エンコードの範囲が広いためバイトシーケンスの解釈が難しい場合がある

## SHIFT_JIS-2004

### 歴史
SHIFT_JIS-2004は、2004年に改訂されたShift_JISのバージョンで、JIS X 0213:2004規格に基づいています。JIS X 0213は、従来のJIS X 0208にない新しい文字や記号を追加した規格です。

### 特徴
- **JIS X 0213のサポート**: 従来のJIS X 0208に加え、JIS X 0213で定義された追加文字をサポートします
- **互換性の保持**: 基本的には従来のShift_JISとの互換性を保持しつつ、新しい文字セットを取り入れています
- **エンコードの拡張**: さらに多くの文字や記号をエンコードできるようになり、日本語の表現力が向上しました

## Windows-31J (cp932)

### 歴史
Windows-31Jは、マイクロソフトによってSHIFT_JISを拡張した文字コードで、Windows環境で広く使用され、CP932とも呼ばれます。

### 特徴
- **互換性の拡張**: SHIFT_JISに独自の拡張を加え、IBM拡張文字も含んでいます
- **Windows依存**: 主にWindows環境で使用され、他のプラットフォームでは互換性の問題が生じる場合がある

## EUC-JP

### 歴史
EUC-JPは、UnixおよびLinux環境で広く使用される文字コードで、1980年代に登場しました。JIS X 0208とJIS X 0201を基にしています。
Solarisで使った記憶があります。

### 特徴
- **エンコードの簡便さ**: 最上位ビットを使用することで、文字の種類（1バイト、2バイト）を判別しやすい
- **互換性**: Unix系システムでの日本語処理には適していましたが、現在ではUTF-8が標準で使用されています

## UTF-8

### 歴史
UTF-8は1990年代に開発され、今日最も広く使用されているUnicodeエンコーディング形式です。ISO 10646とUnicodeを基にしています。

### 特徴
- **可変長エンコード**: 1バイトから4バイトの可変長エンコードを使用します
- **互換性**: UTF-8はASCIIとの互換性があり、英数字を含む多くのテキストで効率的に扱えます
- **グローバル標準**: インターネットや様々なアプリケーションで標準的に使用されています。特にウェブページやメールのエンコーディングとして広く採用されています

## UTF-16

### 歴史
UTF-16は、1990年代にUnicodeの一部として開発されました。主にWindows、Javaプラットフォーム、および一部のデータベースシステムで使用されています。

### 特徴
- **固定長と可変長**: 基本的には2バイトでエンコードされますが、基本多言語面（BMP）外の文字を表現する際にはサロゲートペアを使用することで4バイトになります
- **広範な文字サポート**: Unicodeの広範な文字セットをサポートします

## UTF-32

### 歴史
UTF-32も1990年代にUnicodeの一部として開発されました。全ての文字を固定長の4バイトでエンコードします。

### 特徴
- **固定長エンコード**: 全ての文字が4バイトで表現されるため、文字の長さが一定で管理が容易です
- **メモリ消費**: 全ての文字が固定長の4バイトで表現されるため、大量のメモリを消費し、特にメモリ効率が重要なアプリケーションには適さないことがあります

## サロゲートペア (Surrogate Pair)

### 概要
サロゲートペアは、UTF-16で基本多言語面（BMP）外の文字を表現するための仕組みです。
2つの16ビットコードユニットで1つのUTF-16文字を表現します。

### 特徴
- **高位サロゲート**: 上位ビットが110110から始まる16ビット値。(0xD800から0xDBFFまで)
- **低位サロゲート**: 上位ビットが110111から始まる16ビット値。(0xDC00から0xDFFFまで)

具体的には、「𠮷」は次のようにUTF-16で表現されます：

1. Unicodeコードポイント: U+20BB7
2. 高位サロゲート: 0xD842
3. 低位サロゲート: 0xDFB7

「👍」は次のようにUTF-16で表現されます：
1. Unicodeコードポイント: U+1F44D
2. 高位サロゲート: 0xD83D
3. 低位サロゲート: 0xDC4D

### プログラミング言語での対応
各プログラミング言語では、サロゲートペアの扱い方が異なります。以下にいくつかの例を示します。
サロゲートペアに対応していない場合、2文字としてカウントしてしまったりといった不具合が生じます。

- **Java**:
  `char`型は16ビットのUTF-16コード単位を表すため、1文字が2つの`char`値に分かれる場合があります。これに対応するために、`String`クラスはサロゲートペアを適切に処理し、`codePointAt()`や`codePointCount()`などのメソッドを提供しています
- **C#**:
 `char`型は16ビットのUTF-16コード単位を表します。`string`型はサロゲートペアを適切に処理し、`System.Globalization.StringInfo`クラスは文字列内のサロゲートペアを考慮したメソッドを提供しています
- **JavaScript**:
 文字列は内部的にUTF-16で表現されます。サロゲートペアは2つのコード単位として扱われますが、`String.prototype.charAt()`や`String.prototype.charCodeAt()`などの一部のメソッドはサロゲートペアを適切に処理しません。代わりに、`String.prototype.codePointAt()`や`for...of`ループを使用することが推奨されます
- **Python**:
 文字列はUnicodeとして扱われ、サロゲートペアは単一の文字として適切に処理されます。`len()`関数は文字数を返し、`for`ループは文字列内の各文字を反復処理します。
- **Ruby**:
 文字列はUTF-8でエンコードされますが、文字列操作はサロゲートペアを適切に処理します。`String#length`メソッドは文字数を返し、`String#each_char`メソッドは文字列内の各文字を反復処理します
- **PHP**:
 PHPの内部文字列処理はバイト列として扱われ、特にマルチバイト文字やサロゲートペアの処理には`mbstring`モジュールの使用が推奨されます。`mb_strlen()`関数や`mb_substr()`関数がサロゲートペアを適切に処理します
- **Rust**:
 Rustでは文字列は内部的にUTF-8でエンコードされます。`char`型はUnicodeのスカラー値を表し、サロゲートペアは`char`型では表現されません。文字列操作はサロゲートペアを適切に処理します。例えば、`String::chars()`メソッドは文字列をUnicodeのスカラー値のイテレータに変換し、サロゲートペアを単一の`char`値として扱います。ただし、`String::len()`メソッドはバイト数を返すため、サロゲートペアを含む文字列の文字数を数える場合は`String::chars().count()`を使う必要があります。

## 絵文字 (Emoji)

### 概要
絵文字は、表情を表したり、物を表したりする文字です。1999年に日本の携帯電話で登場し発展しました。
2010年にUnicode 6.0で正式に採用されました。

### 特徴
- **サロゲートペア**: 多くの絵文字はサロゲートペアを使用してUTF-16で表現されます

### 絵文字のサロゲートペア

例えば、「👍🏽」という絵文字（サムズアップ👍 + 中くらいのスキントーン）は、次のようにUTF-16で表現されます：

1. サムズアップ（U+1F44D）👍
   - 高位サロゲート: 0xD83D
   - 低位サロゲート: 0xDC4D

2. 中くらいのスキントーン（U+1F3FD）
   - 高位サロゲート: 0xD83C
   - 低位サロゲート: 0xDFFD

したがって、「👍🏽」は以下のように4つの16ビットコードユニットで表現されます：

1. 高位サロゲート（サムズアップ）：0xD83D
2. 低位サロゲート（サムズアップ）：0xDC4D
3. 高位サロゲート（中くらいのスキントーン）：0xD83C
4. 低位サロゲート（中くらいのスキントーン）：0xDFFD

## まとめ

本記事では、文字コードの歴史と特徴について紹介しました。
現在では、UTF-8が最も広く使用されていますが、レガシーシステムや特定の環境では他のエンコード方式が依然として使われている感じですね。