UTF-8とは
UTF-8(ユーティーエフエイト)は、
Unicodeと
ISO/IEC 10646|ISO_IEC 10646で使用される、1文字を1~4バイトの可変長で表現する文字符号化方式です。正式名称は、
ISO/IEC 10646|ISO_IEC 10646では“UCS Transformation Format 8”、
Unicodeでは“
Unicode Transformation Format-8”と定められています。両規格間ではコードの重複範囲において互換性があります。また、RFCにも仕様が記述されています。
UTF-8は、2バイト目以降に
ASCII文字が出現しないように設計されており、ファイルシステムでも安全に使用できることから「UTF-FSS (File System Safe)」とも呼ばれます。旧名称はUTF-2です。データ交換やファイル形式として、現在では広く利用される傾向にあります。
エンコード体系
UTF-8は、
ASCII文字との互換性を保つため、
ASCII文字は1バイトで表現し、それ以外の文字は2~4バイトで表現します。4バイトのシーケンスでは、最大21
ビット(0x1FFFFF)まで表現できますが、
Unicodeの範囲外となる17面以降の文字は受け付けません。また、5~6バイトの表現は、かつての規格では
Unicode範囲外の文字に使用されていましたが、現在の規格では不正なシーケンスとされます。
符号化においては、最小のバイト数で表現することが求められます。例えば、
ASCII文字は1バイトで表現するのが基本ですが、2バイト以上でも表現可能です。しかし、バイト数ごとの下限が設けられているため、このような冗長な符号化は避けられます。
UTF-8の
ビットパターンは以下の通りです。
1バイト文字:0xxxxxxx
2バイト文字:110xxxxx 10yyyyyy
3バイト文字:1110xxxx 10yyyyyy 10zzzzzz
4バイト文字:11110xxx 10yyyyyy 10zzzzzz 10wwwwww
ここで、x, y, z, wの部分に、
Unicodeの符号位置を2進数で右詰めで格納します。先頭の連続する"1"の数で、その文字のバイト数がわかります。また、2バイト目以降は"10"で始まるため、文字の区切りを確実に判定できます。具体的には、先頭
ビットが"0"なら1バイト文字、"10"なら2バイト以上の文字の2バイト目以降、"110"なら2バイト文字、"1110"なら3バイト文字、"11110"なら4バイト文字です。
特徴
利点
ASCII互換性:ASCII文字をそのまま扱えるため、既存のASCII対応ソフトウェアをほとんど変更せずに利用できます。
文字境界の判定:バイト列の任意の位置から、文字の先頭を容易に判定できます。
検索の安全性:文字列検索がバイト列検索として行えるため、マルチバイト文字の途中で誤ってマッチすることがありません。
バイト順の影響を受けない:UTF-16やUTF-32と異なり、バイト単位の入出力を行うため、バイト順による影響を受けません。
サロゲートペアが不要:21ビットまで表現できるため、UTF-16のようなサロゲートペアを使用する必要がありません。
データサイズの効率性:
ASCII文字が主体の文書では、データサイズをほとんど増やさずに
Unicodeのメリットを享受できます。
ソートの整合性:UTF-8でソートした結果は、Unicode符号位置の辞書順ソート結果と一致します。
欠点
データサイズの増加:
漢字や仮名など、従来のマルチバイト文字で2バイトで表現されていたものが3バイトになるため、データサイズが増加する場合があります。特に、非
ASCIIの
ラテン文字なども2バイトになるため、データサイズが増大する可能性があります。
冗長な符号化によるセキュリティリスク:最小バイト数で表現されない符号は不正とみなされますが、一部のプログラムでは受け入れてしまい、セキュリティ上の問題を引き起こす可能性があります。
サロゲートペアの扱い
UTF-8では、UTF-16のサロゲートペアをそのまま変換するのではなく、一度Unicodeの符号位置にデコードしてから変換します。サロゲートペアをそのままUTF-8で符号化したようなバイト列は、不正なUTF-8とされます。
サロゲートペアをそのまま残す符号化方式として、CESU-8 (Compatibility Encoding Scheme for UTF-16: 8-Bit) があります。これは、主に旧バージョンのOracle Databaseなどで利用されており、サロゲートペアを3オクテットのペアで表現します。現在のOracle Databaseでは、UTF-8を「AL32UTF8」、CESU-8を「UTF8」として扱っています。
MySQLでも、古いバージョンでは「utf8」を指定すると4オクテットのUTF-8を扱えず、CESU-8相当の符号化が必要になります。4オクテット対応のUTF-8は「utf8mb4」として別途定義されています。
Javaの一部の内部実装でも、Modified UTF-8としてサロゲートペアをそのまま残す仕様が用いられています。
セキュリティ
UTF-8のエンコードには冗長性があり、同じ文字を複数の表現で符号化することが可能です。以前はこのような表現も許容されていましたが、現在では最小バイト数による表現以外は不正なUTF-8シーケンスとみなされます。これは、ディレクトリトラバーサルなどの攻撃を防ぐためです。
また、UTF-8の定義が5バイト以上の表現を許容していることで、バグのあるシステムではバッファオーバーフローが発生する可能性があります。
文字種
UTF-8で表現できる文字は、Unicodeで定義されているすべての文字です。
バイト順マーク (BOM)
UTF-8で符号化されたテキストデータは、バイト順マーク(BOM)を付加する必要はありません(エンディアンに関わらず同じ内容になるため)。しかし、UTF-8で符号化されていることを示すために、先頭にEF BB BFのシーケンス(U+FEFFのUTF-8表現)をBOMとして付加することが許容されます。この3バイトは、ZERO WIDTH NO-BREAK SPACEを表しますが、データ先頭ではBOMの機能を持たせます。
BOMの問題点
BOM付きのUTF-8に対応しないプログラムは多く、BOMを余分なデータとみなすため、問題が発生することがあります。
実行可能スクリプト:
Unix系OSでは、BOMがあるとスクリプトの実行に失敗する場合があります。
PHP:BOMがあるとheader()関数の実行に失敗する原因になります。
シェーダーコンパイラ:BOMを処理できず、コンパイルエラーが発生します。
一方、一部のテキスト処理アプリケーションではBOMを前提とした動作をするため、BOMがないとUTF-8と認識できないことがあります。
Microsoft ExcelでCSVファイルを開く場合など、文字化けが発生する可能性があります。
BOMなしUTF-8をデフォルトにする動きもありますが、BOMの有無で動作が変わるプログラムがあるため、注意が必要です。
プロトコルがUTF-8であることを強制している場合はBOMを禁止すべきで、その場合は先頭にあるBOMはZERO WIDTH NO-BREAK SPACEとみなされます。
まとめ
UTF-8は、
ASCIIとの互換性を保ちつつ、
Unicodeの全ての文字を扱うことができる優れた文字符号化方式です。しかし、その特徴を理解し、適切な設定で使用しないと、予期しない問題が発生する可能性があります。特に、セキュリティ上の注意やBOMの取り扱いには注意が必要です。
参考資料
RFC 3629
Unicode
関連項目
*
文字コード