この記事では、 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 対応プログラムが必要です。これらのファイルには多くのゼロバイトが含まれているため、このようなファイルを表す文字列は、一般的なnull 終端文字列処理ロジックでは操作できません。[a]このロジックを使用した文字列処理が普及しているため、 WindowsやJavaなどの UTF-16 システムのコンテキストでも、UTF-16 テキストファイルは一般的に使用されていません。むしろ、ASCII やISO-8859-1などの古い 8 ビットエンコードが引き続き使用され、Unicode サポートが完全に放棄されているか、Unicode の代わりに UTF-8 が使用されています。[要出典]まれな反例として、Mac OS X 10.3 Pantherで導入された "strings" ファイルがあります。これは、アプリケーションの国際化バージョンのメッセージを検索するために使用されます。デフォルトでは、このファイルはUTF-16でエンコードされており、「UTF-8でエンコードされたファイルは動作が保証されません。」[1]
XMLは従来UTF -8でエンコードされており[引用が必要]、すべてのXMLプロセッサは少なくともUTF-8とUTF-16をサポートしている必要があります。[2]
効率
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) は、ほぼすべてのラテン文字アルファベットのほか、ギリシャ語、キリル文字、コプト語、アルメニア語、ヘブライ語、アラビア語、シリア語、ターナ語、N'Koで使用される残りの文字を表します。この範囲の文字を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 ビットが必要です。
U+0800からU+FFFFの範囲のコードポイントよりもASCIIコードポイントの方が多い場合、ファイルはUTF-8の方がUTF-16よりも短くなります。UTF-8を推奨する人たちは、高範囲の文字のみを使用する言語で書かれた実際の文書は、スペース、数字、句読点、改行、HTML、ラテン文字で書かれた埋め込み単語や頭字語を多用するため、UTF-8の方が短いことが多いと主張しています。[3]対照的に、UTF-32は、U+10000未満のコードポイントがない限り、常に長くなります。
UTF-EBCDICのすべての印刷可能な文字は、少なくとも UTF-8 と同じバイト数を使用しますが、C1 制御コードを 1 バイトとしてエンコードできるように決定されたため、ほとんどの文字はそれ以上のバイト数を使用します。7 ビット環境では、UTF-7 は、ほぼすべての種類のテキストに対して、quoted-printableまたはbase64と他の Unicode エンコードの組み合わせよりもスペース効率に優れています[詳細な説明が必要] (以下の「7 ビット環境」を参照)。
処理時間
UTF-8 や UTF-16 などの可変長エンコーディングのテキストは、コード ポイントで作業する場合よりも、個々のコード ユニットで作業する必要がある場合は処理が難しくなります。コード ユニットのシーケンスの検索では区切りは考慮されないため、文字のサイズが可変であるかどうかは検索に影響しません。ただし、エンコーディングが自己同期化されている必要があり、UTF-8 と UTF-16 はどちらも自己同期化されています。よくある誤解は、「 n番目の文字を見つける」必要があり、これには固定長エンコーディングが必要であるということですが、実際の使用では、nという数値はn−1文字を調べることによってのみ得られるため、いずれにしても順次アクセスが必要になります。[要出典]
あるエンディアン順序の文字シーケンスを、異なるエンディアン順序のマシンにロードして効率的に使用するには、追加の処理が必要です。文字は、使用前に変換するか、2 つの異なるシステムで処理されます。UTF-8 などのバイトベースのエンコードでは、この問題は発生しません。[なぜ? ] UTF-16BEとUTF-32BEはビッグ エンディアンであり、UTF-16LEとUTF-32LEはリトルエンディアンです。
処理の問題
処理のために、フォーマットは検索や切り捨てが容易で、一般的に安全に処理できるものでなければなりません。[要出典]通常の 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 を使用すると、基本多言語面外の文字が特別なケースとなり、その処理に関する見落としのリスクが高まります。とはいえ、サロゲート ペアを誤って処理するプログラムは、シーケンスの結合にも問題を抱えている可能性が高いため、UTF-32 を使用しても、マルチコード単位文字の不適切な処理というより一般的な問題は解決されない可能性があります。
保存されているデータ (ファイルの内容や名前など) が UTF-8 である場合、API として UTF-16 または UTF-32 を使用するシステムを作成することは非常に困難です。これは、UTF-8 で使用されるバイト配列に物理的に無効なシーケンスが含まれる可能性があるという、見落とされがちな事実によるものです。たとえば、UTF-16 API を使用して無効な UTF-8 ファイル名を修正することは不可能です。UTF-16 文字列をその無効なファイル名に変換できないためです。その逆は当てはまりません。無効な UTF-16 を一意の (技術的には無効ですが) UTF-8 文字列に変換するのは簡単なので、UTF-8 API は UTF-8 と UTF-16 の両方のファイルと名前を制御できるため、このような混在環境では UTF-8 が好まれます。UTF-16 システムで使用されている残念ですがはるかに一般的な回避策は、UTF-8 をCP-1252などの他のエンコードとして解釈し、非 ASCII データの mojibake を無視することです。
通信と保管用
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 範囲のコード ポイントあたりのバイト数を示しています。必要な追加コメントは表に含まれています。これらの数値は、テキスト ブロックの先頭と末尾のオーバーヘッドが無視できるほど小さいことを前提としています。
注意:以下の表は、コード ポイントあたりのバイト数を示しており、ユーザーに表示される「文字」(または「書記素クラスター」)あたりのバイト数を示していません。 1 つの書記素クラスターを記述するには複数のコード ポイントが必要になることがあるため、UTF-32 であっても、文字列を分割または連結する際には注意が必要です。
8ビット環境
7ビット環境
この表はすべての特殊なケースを網羅しているわけではないため、推定と比較のみに使用してください。エンコード内のテキストのサイズを正確に判断するには、実際の仕様を参照してください。
エンディアンはサイズに影響しません(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バイト。
quoted-printable または 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 には、圧縮方式のより詳細な比較が記載されています。
歴史的: UTF-5 と UTF-6
ドメイン名の国際化(IDN)のために UTF-5 と UTF-6 の提案がなされてきました。UTF-5 提案では32 進数エンコードが使用され、Punycodeは (他の点では厳密には異なりますが) 36 進数エンコードです。5ビットのコード単位を表すUTF-5 という名前は、2 5 = 32という式で説明されます。 [4] UTF-6 提案では、UTF-5 に連続長エンコードが追加されました。ここで、6 は単にUTF-5 プラス 1を表します。[5] IETF IDN WG は、後にこの目的のために、より効率的なPunycodeを採用しました。[6]
真剣に追求されていない
UTF-1 は本格的に受け入れられることはありませんでした。UTF-8 の方がはるかに頻繁に使用されています。
ノネット エンコーディングUTF-9 と UTF-18はエイプリル フールの RFCジョーク仕様ですが、UTF-9 は機能するノネット Unicode 変換形式であり、UTF-18 は機能するノネット エンコーディングであり、Unicode 12 以下のすべての非私的使用コード ポイントで機能しますが、補足私的使用領域またはUnicode 13 以降の一部では使用できません。
注記
- ^ 文字列を終了させるためにヌル文字を使用しないASCII ソフトウェアは、 UTF-16 および UTF-32 でエンコードされたファイルを正しく処理します (そのようなファイルに ASCII サブセット文字のみが含まれている場合、ヌル文字が埋め込まれた通常の ASCII として表示されます) が、そのようなソフトウェアは一般的ではありません。[引用が必要]
- ^ 対照的に、UTF-16 では、偶数バイトが欠落しても最大 1 文字しか文字化けしません。
参考文献
- ^ 「Apple Developer Connection: 国際化プログラミングトピック: 文字列ファイル」。
- ^ 「エンティティの文字エンコーディング」。拡張マークアップ言語 (XML) 1.0 (第 5 版)。ワールド ワイド ウェブ コンソーシアム。2008 年。
- ^ “UTF-8 Everywhere”. utf8everywhere.org . 2022年8月28日閲覧。
- ^ Seng, James、「UTF-5、Unicode と ISO 10646 の変換形式」、2000 年 1 月 28 日
- ^ Welter, Mark; Spolarich, Brian W. (2000 年 11 月 16 日). 「UTF-6 - ID 用のもう 1 つの ASCII 互換エンコーディング」. Ietf Datatracker . 2016 年 5 月 23 日時点のオリジナルよりアーカイブ。2016 年4 月 9 日閲覧。
- ^ 「国際化ドメイン名(idn)」。インターネット技術タスクフォース。 2023年3月20日閲覧。
