Unicodeエンコーディングとは?
Unicodeは、人間の言語で使用されるすべての文字にコードポイントと呼ばれる一意の番号を割り当てる、普遍的な文字エンコーディング標準です。Unicode以前は、互換性のない多数のエンコーディングシステムが存在しました。あるシステムでロシア語で書かれた文書は、別のシステムでは読めませんでした。Unicodeは、150以上の言語系譜と14万以上の文字をカバーする単一の統合文字セットを提供することでこれを解決します。
Unicode自体はエンコーディングではありません。これは文字レパートリーです。コードポイントをバイトとして保存する方法であるエンコーディング層は、UTF-8、UTF-16、UTF-32などのエンコーディング形式によって処理されます。コードポイントとそのバイト表現の違いを理解することが、エンコーディングバグを回避する鍵です。
コードポイント
すべてのUnicode文字には、U+ の後に16進数が続くコードポイントがあります。文字Aは U+0041、ユーロ記号は U+20AC、絵文字😀は U+1F600 です。
コードポイントは17のプレーンに編成され、各プレーンには65,536文字が含まれます。最初のプレーン(プレーン0)は基本多言語面(BMP)で、ラテン文字、ギリシャ文字、キリル文字、CJKなどを含む最も一般的な文字が含まれています。プレーン1〜16には、絵文字、歴史的文字、希少なCJK文字などの補助文字が含まれています。
| プレーン | 範囲 | 名前 |
|---|---|---|
| 0 | U+0000 ~ U+FFFF | 基本多言語面(BMP) |
| 1 | U+10000 ~ U+1FFFF | 補助多言語面(SMP) |
| 2 | U+20000 ~ U+2FFFF | 補助漢字面(SIP) |
| 3-13 | U+30000 ~ U+DFFFF | 未割り当て |
| 14 | U+E0000 ~ U+EFFFF | 補助特殊用途面(SSP) |
| 15-16 | U+F0000 ~ U+10FFFF | 私用面 |
UTF-8、UTF-16、UTF-32
これら3つのエンコーディング形式は、コードポイントをバイトにマッピングする方法が異なります。
UTF-8
UTF-8はWeb上で支配的なエンコーディングです。1文字あたり1〜4バイトを使用し、ASCIIと後方互換性があります。ASCII範囲(U+0000 ~ U+007F)の文字は1バイトを使用します。ヨーロッパの言語系譜の文字は2バイトを使用します。CJK文字と絵文字は3〜4バイトを使用します。
| コードポイント範囲 | バイト1 | バイト2 | バイト3 | バイト4 |
|---|---|---|---|---|
| U+0000 - U+007F | 0xxxxxxx | |||
| U+0080 - U+07FF | 110xxxxx | 10xxxxxx | ||
| U+0800 - U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
| U+10000 - U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
UTF-8の利点:
- ASCIIテキストは有効なUTF-8(変換不要)
- 自己同期:常に文字境界を見つけられる
- バイト順序の問題なし(リトルエンディアン/ビッグエンディアン)
- ラテン文字テキストに最も容量効率が良い
UTF-16
UTF-16はBMP文字に2バイト(1コードユニット)、補助文字に4バイト(2コードユニット、サロゲートペアと呼ばれる)を使用します。Windows、Java、JavaScriptは内部でUTF-16を使用しています。
UTF-16にはバイト順序の問題があります。UTF-16ファイルは、リトルエンディアン(UTF-16LE)かビッグエンディアン(UTF-16BE)かを指定する必要があり、通常は先頭にBOM(バイトオーダーマーク)を使用します。
UTF-32
UTF-32はすべてのコードポイントに正確に4バイトを使用します。シンプルですが非効率的です。純粋なASCIIファイルは4倍のサイズになります。UTF-32は実際にはほとんど使用されません。
比較
| 特徴 | UTF-8 | UTF-16 | UTF-32 |
|---|---|---|---|
| 1文字あたりのバイト数 | 1-4 | 2または4 | 4 |
| ASCII互換性 | あり | なし | なし |
| Web使用率 | ~98% | ~2% | <0.01% |
| BOM必要 | いいえ | はい | はい |
| 一般的な使用先 | Web、Linux、JSON | Windows、Java、JS | 内部処理 |
エンコーディングバグ
最も一般的なエンコーディングバグは、バイトを文字として扱うことです。UTF-8文字列をLatin-1(ISO 8859-1)として解釈すると、アクセント付き文字が文字化けした記号として表示されます。これは、エンコーディングが宣言されていない場合や、ツールが誤ったエンコーディングを想定した場合に発生します。
もう1つの一般的な問題は、文字の代わりにバイトをカウントすることです。UTF-8では、文字列「café」は4文字ですが、éが2バイトを使用するため5バイトです。PHPの strlen はデフォルトでバイトをカウントしますが、mb_strlen は文字をカウントします。
プログラミング例
// PHP - UTF-8では常にmb_*関数を使用
$text = 'café ☕';
echo strlen($text); // 8バイト(誤ったカウント)
echo mb_strlen($text, 'UTF-8'); // 6文字
// Unicodeコードポイントのエンコード/デコード
echo mb_convert_encoding($text, 'UTF-16', 'UTF-8');
# Python 3 - 文字列はデフォルトでUnicode
text = 'café ☕'
print(len(text)) # 6文字
bytes_utf8 = text.encode('utf-8')
bytes_utf16 = text.encode('utf-16')
print(bytes_utf8) # b'caf\xc3\xa9 \xe2\x98\x95'
// JavaScript - 文字列は内部的にUTF-16
let text = 'café ☕';
console.log(text.length); // 6(ただし絵文字は2とカウントされる場合あり)
// UTF-8バイトとしてエンコード
let encoder = new TextEncoder();
let bytes = encoder.encode(text);
console.log(bytes); // Uint8Array(8)
オンラインツール
Help2CodeのUnicodeエンコーダー&デコーダーは、テキストをUnicodeコードポイントに変換し、UTF-8、UTF-16、UTF-32表現間で変換します。エンコーディング問題のデバッグやUnicodeの学習に役立ちます。
結論
Unicodeエンコーディングは、国際的なテキストを扱うすべての開発者にとって不可欠な知識です。UTF-8はWebの標準であり、デフォルトとして使用すべきです。コードポイントとバイト表現の違いを理解することで、最も一般的なテキストエンコーディングバグを回避できます。Unicodeエンコーダー&デコーダーを使用してエンコーディングを試したり、エンコーディング問題をデバッグしたりしてください。