この記事では、 8ビットクリーンな環境と、最上位ビットがセットされたバイト値の使用を禁止する環境という2種類の環境におけるUnicodeエンコーディングを比較します。当初、このような禁止事項は7ビットのデータのみを使用するリンクを可能にしていましたが、一部の標準規格には依然として残っているため、標準規格に準拠するソフトウェアは、これらの制限に従うメッセージを生成しなければなりません。Unicodeの標準圧縮方式とUnicodeのバイナリ順序圧縮は、そのサイズを単純に定量化することが難しいため、比較表から除外されています。
ASCII文字のみを含むUTF-8ファイルは、ASCIIファイルと同一です。従来のプログラムは、非ASCII文字が含まれている場合でも、UTF-8エンコードされたファイルを一般的に処理できます。たとえば、C言語のprintf関数は、書式文字列を定義するためにASCII文字「%」のみを探すため、UTF-8文字列を出力できます。その他のバイトはすべて変更されずに出力されます。
UTF-16とUTF-32 はASCII ファイルと互換性がないため、ファイルに ASCII サブセットの文字しか含まれていないことがわかっている場合でも、表示、印刷、操作するには Unicode 対応プログラムが必要です。これらのファイルを表す文字列は、ゼロ バイトが多数含まれているため、一般的なヌル終端文字列処理ロジックでは操作できません。[ a ]このロジックを使用した文字列処理が普及しているため、 WindowsやJavaなどの UTF-16 システムのコンテキストでも、UTF-16 テキスト ファイルは一般的に使用されていません。むしろ、ASCII やISO-8859-1などの古い 8 ビット エンコーディングが引き続き使用され、Unicode サポートは完全に放棄されるか、Unicode には UTF-8 が使用されます。
XMLは慣例的にUTF-8でエンコードされ、すべてのXMLプロセッサは少なくともUTF-8とUTF-16をサポートする必要があります。[ 1 ]
UTF-8ではUnicode文字をエンコードするために8、16、24、または32ビット(1~4バイト)が必要であり、 UTF-16では16ビットまたは32ビットが必要であり、UTF-32では常に32ビットが必要です。
最初の 128 個の Unicodeコード ポイント(U+0000 ~ U+007F) は、C0 コントロールと基本ラテン文字に使用され、ASCII に対応しており、UTF-8 では 8 ビット、UTF-16 では 16 ビット、UTF-32 では 32 ビットを使用してエンコードされます。次の 1,920 文字 (U+0080 ~ U+07FF) は、ほぼすべてのラテン文字アルファベット、ギリシャ文字、キリル文字、コプト文字、アルメニア文字、ヘブライ文字、アラビア文字、シリア文字、ターナ文字、ンコ文字で使用される残りの文字を表します。この範囲の文字は、UTF-8 と UTF-16 では 16 ビット、UTF-32 では 32 ビットを使用してエンコードする必要があります。 U+0800 から U+FFFF までは、基本多言語プレーンの残りの文字であり、世界のほとんどの言語の残りの文字を表すことができます。UTF-8 では文字をエンコードするのに 24 ビットが必要ですが、UTF-16 では 16 ビット、UTF-32 では 32 ビットが必要です。補助プレーンの文字を表すコード ポイント U+010000 から U+10FFFF は、UTF -8、UTF-16、UTF-32 で 32 ビットが必要です。
UTF-8 のファイルは、U+0800 から U+FFFF の範囲のコード ポイントの数よりも ASCII コード ポイントの数が多い場合、UTF-16 よりも短くなります。UTF-8 を推奨形式とする支持者は、高範囲の文字のみを使用する言語で書かれた実際の文書は、スペース、数字、句読点、改行、HTMLまたはXMLマークアップ ( docx ファイルやodtファイルなど)、ラテン文字で書かれた埋め込み単語や頭字語が多用されるため、UTF-8 の方が短い場合が多いと主張しています。[ 2 ]一方、UTF-32 は、U+10000 未満のコード ポイントがない限り、常に長くなります。
UTF-EBCDICの印刷可能な文字はすべて、UTF-8 と同等以上のバイト数を使用し、C1 制御コードを単一バイトとしてエンコードできるようにしたため、ほとんどの文字はそれ以上のバイト数を使用します。7 ビット環境では、UTF-7は、ほとんどすべての種類のテキストにおいて、他の Unicode エンコーディングとquoted-printableまたはbase64の組み合わせよりもスペース効率が優れています(下記の「7 ビット環境」を参照)。
UTF-8 や UTF-16 のような可変長エンコーディングのテキストは、コードポイントではなく個々のコードユニットを扱う必要がある場合、処理が難しくなります。検索は、文字のサイズが可変かどうかに関係なく、コードユニットのシーケンスを検索する際には分割を考慮しないため、影響を受けません。ただし、エンコーディングが自己同期的である必要があり、UTF-8 と UTF-16 はどちらも自己同期的です。よくある誤解として、「 n番目の文字を見つける」必要があり、そのためには固定長エンコーディングが必要だというものがありますが、実際の使用では、nという数はn-1文字を調べることによってのみ得られるため、いずれにしてもシーケンシャルアクセスが必要になります。
処理においては、フォーマットは検索や切り捨てが容易で、一般的に安全に処理できるものでなければなりません。通常のUnicodeエンコーディングはすべて、何らかの固定サイズのコードユニットを使用します。エンコードするフォーマットとコードポイントに応じて、これらのコードユニットの1つ以上がUnicodeコードポイントを表します。検索や切り捨てを容易にするために、シーケンスはより長いシーケンス内、または他の2つのシーケンスの境界を越えて出現してはなりません。UTF-8、UTF-16、UTF-32、UTF-EBCDICはこれらの重要な特性を備えていますが、UTF-7とGB 18030は備えていません。
固定サイズの文字は便利な場合もありますが、コードポイントごとに固定バイト数がある場合(UTF-32 のように)、文字の組み合わせにより、表示される文字ごとに固定バイト数はありません。このような互換性の問題や、異なるエンコーディング方式間のその他の癖を考慮すると、インターフェース全体およびインターフェース間で同じ(または互換性のある)プロトコルを使用して Unicode データを処理すること(たとえば、API/ライブラリの使用、クライアント/サーバー モデルでの Unicode 文字の処理など)は、一般的にパイプライン全体を簡素化すると同時に、潜在的なバグの原因を排除することができます。
UTF-16が広く普及しているのは、多くのAPIがUnicodeが16ビット固定幅(UCS-2と呼ばれる)だった時代にまで遡るためです。しかし、UTF-16を使用すると、基本多言語面(BMP)外の文字が特殊なケースとなり、それらの処理に関する見落としのリスクが高まります。とはいえ、サロゲートペアの処理に問題のあるプログラムは、シーケンスの結合にも問題を抱えている可能性が高いため、UTF-32を使用しても、マルチコードユニット文字の処理不良というより一般的な問題は解決されないでしょう。
保存されているデータにUTF-8(ファイルの内容やファイル名など)が含まれている場合、UTF-16またはUTF-32をAPIとして使用するシステムを作成するのは非常に困難です。これは、UTF-8で使用されるバイト配列が物理的に無効なシーケンスを含む可能性があるという、しばしば見落とされがちな事実によるものです。たとえば、無効なUTF-8ファイル名をUTF-16 APIで修正することは不可能です。なぜなら、有効なUTF-16文字列では、その無効なファイル名に変換できないからです。しかし、その逆は成り立ちません。無効なUTF-16を一意の(技術的には無効な)UTF-8文字列に変換することは容易であるため、UTF-8 APIはUTF-8とUTF-16の両方のファイルとファイル名を制御でき、このような混在環境ではUTF-8が推奨されます。UTF-16システムでよく用いられる、残念ではあるもののより一般的な回避策は、UTF-8をCP-1252などの他のエンコーディングとして解釈し、 ASCII以外のデータの文字化けを無視することです。
UTF-16とUTF-32にはエンディアンが定義されていないため、バイト指向ネットワークで受信する場合やバイト指向ストレージから読み込む場合は、バイト順序を選択する必要があります。これは、テキストの先頭にバイト順序マークを使用するか、ビッグエンディアンを仮定することで実現できます(RFC 2781)。UTF -8、UTF-16BE、UTF-32BE、UTF-16LE、UTF-32LEは単一のバイト順序で標準化されているため、この問題はありません。
バイト ストリームが破損した場合、一部のエンコーディングは他のエンコーディングよりも回復が優れています。UTF-8 と UTF-EBCDIC はこの点で最も優れており、破損または欠落したバイトの後、次のコード ポイントの開始時に常に再同期できます。GB 18030 は次の ASCII 非数値まで回復できません。UTF-16 は変更されたバイトを処理できますが、奇数個の欠落バイトは処理できず、後続のすべてのテキストが文字化けします (ただし、一般的でない文字や割り当てられていない文字が生成されます)。[ b ]ビットが失われる可能性がある場合、すべてのビットが後続のテキストを文字化けしますが、UTF-8 は再同期できます。これは、不正なバイト境界によって、数バイトより長いほとんどすべてのテキストで無効な UTF-8 が生成されるためです。
以下の表は、異なるUnicode範囲におけるコードポイントあたりのバイト数を示しています。必要な補足説明は表中に含まれています。これらの数値は、テキストブロックの先頭と末尾におけるオーバーヘッドが無視できる程度であることを前提としています。
この表はすべての特殊なケースを網羅しているわけではないため、あくまで概算や比較のためにのみ使用してください。エンコーディングにおけるテキストのサイズを正確に把握するには、実際の仕様書を参照してください。
エンディアンはサイズに影響しません ( UTF-16BEとUTF-32BEは、それぞれUTF-16LEとUTF-32LEと同じサイズです)。quoted-printable の下で UTF-32 を使用することは非常に非現実的ですが、実装すると、コード ポイントごとに 8~12 バイト (平均で約 10 バイト) になります。つまり、BMP の場合、各コード ポイントは、quoted-printable/UTF-16 の同じコードよりも正確に 6 バイト多く占有します。Base64/UTF-32 では、どのコードポイントでも5 + 1/3バイトになります。
引用符付き印刷可能文字またはUTF-7エンコーディングにおけるASCII制御文字は、直接表現することも、エンコード(エスケープ)することも可能です。特定の制御文字をエスケープする必要があるかどうかは様々な状況によって異なりますが、テキストデータ内の改行文字は通常、直接エンコードされます。
BOCU-1とSCSUは、Unicodeデータを圧縮する2つの方法です。これらのエンコーディングは、テキストの使用頻度に依存します。ほとんどのテキストは、ラテン文字、キリル文字、ギリシャ文字など、同じ文字体系を使用します。このような通常の使用状況により、多くのテキストをコードポイントあたり約1バイトまで圧縮できます。これらのステートフルなエンコーディングでは、文字列の任意の位置にあるテキストにランダムにアクセスすることがより困難になります。
これら2つの圧縮方式は、 zipやbzip2などの他の圧縮方式ほど効率的ではありません。これらの汎用圧縮方式は、長いバイト列をわずか数バイトに圧縮できます。SCSUとBOCU-1の圧縮方式では、UTF-8、UTF-16、またはUTF-32でエンコードされたテキストの理論上の25%を超える部分を圧縮することはできません。他の汎用圧縮方式では、元のテキストサイズの10%まで簡単に圧縮できます。汎用方式では、高い圧縮率を得るために、より複雑なアルゴリズムとより長いテキストチャンクが必要となります。
Unicodeテクニカルノート第14号には、圧縮方式のより詳細な比較が記載されています。
ドメイン名の国際化(IDN)のために UTF-5 と UTF-6 の提案がなされてきました。UTF-5 の提案では32 進数エンコーディングが使用されていますが、Punycodeは (厳密にはそうではありませんが) 36 進数エンコーディングです。5ビットのコード単位のUTF-5という名前は、2 5 = 32という式で説明されています。RFCのセクション 2、「UTF-5 の定義」では、UTF-5 の特異な構造が明確にされています。[ 3 ]
UTF-6 の提案では、UTF-5 にランニング レングス エンコーディングが追加されました。ここで6 は単にUTF-5 プラス 1を意味します。[ 4 ]
UTF-1は本格的に普及することはなかった。UTF-8の方がはるかに頻繁に使用されている。
ノンネットエンコーディングであるUTF-9 と UTF-18 は、エイプリルフールの RFCジョーク仕様ですが、UTF-9 は機能するノンネット Unicode 変換フォーマットであり、UTF-18 は Unicode 12 以前のすべての非プライベート使用コードポイントに対して機能するノンネットエンコーディングですが、補足プライベート使用領域やUnicode 13 以降の一部のコードポイントには対応していません。