UTF-8がエンコードでいくつかのビットを浪費する理由


16

ウィキペディアの記事によると、UTF-8の形式は次のとおりです。

最初のコード最後のコードバイトバイト1バイト2バイト3バイト4
ポイントポイント使用済み
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
xは、このビットを使用してコードポイントを選択することを意味します。

これにより、各継続バイトで2ビット、最初のバイトで1ビットが無駄になります。UTF-8が次のようにエンコードされないのはなぜですか?

最初のコード最後のコードバイトバイト1バイト2バイト3
ポイントポイント使用済み
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

コードポイントがBasic Multilingual Planeから外れている場合、またはコードポイントが範囲[U + 800、U + 3FFF]にある場合、1バイトを節約します。

UTF-8がより効率的な方法でエンコードされないのはなぜですか?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt提案されたエンコードは、元のFSS / UTFの提案に似ています。ケントンプソンとロブパイクは、自己同期プロパティを望んでいました。
-ninjalj

4
また、エンコードは、非ASCII文字の表現のどの部分にもASCIIコード値が表示されないことを保証していないようです。FSS / UTFおよびUTF-8は、レガシープログラム(たとえば、区切り文字としてASCII NULおよびスラッシュ(パス区切り文字)を使用するプログラム)で動作するように設計されています。
ninjalj

回答:


25

これは、マルチバイトシーケンスの最中であることを検出できるようにするためです。UTF-8データを見ると10xxxxxx、が表示されている場合、マルチバイト文字の途中にいることがわかり、0xxxxxxまたはが表示されるまでストリーム内でバックアップする必要があることがわかります11xxxxxx。スキームを使用すると、バイト2または3は、次のいずれ0xxxxxxxかのパターンで簡単に終わる可能性があります11xxxxxx

また、保存される量は、エンコードする文字列データの種類によって完全に異なることに注意してください。アジアのテキストであっても、ほとんどのテキストでは、通常のテキストで4バイト文字が表示されることはほとんどありません。また、テキストがどのように見えるかについての人々の素朴な見積もりは、しばしば間違っています。日本語、中国語、韓国語の文字列を含むUTF-8用にローカライズされたテキストがありますが、実際にはほとんどのスペースを占めるのはロシア語です。(私たちのアジアの文字列には、固有名詞や句読点などにローマ字が散在していることが多いため、平均的な中国語の単語は1〜3文字であるのに対して、平均的なロシア語の単語はもっと多いためです。)


しかし、私が計画しているのは、キャラクターの物ggingいであることがわかっている場所から始める場合、キャラクターに何バイトあるかを確認して、次のキャラクターの物ggingいに行くことができます。
qbt937 14年

11
承知しました。スキームはより情報が密ですが、UTF-8が提供する重要な機能はありません。一般に、人々は安全性を好むため、UTF-8が可能です。また、スキームが実際に効率的であることを実際に証明するには、実際のテキストを使用して統計を提供する必要があります。ほとんどの実際のテキストでは、あなたのスキームは非常に些細な量を節約するため、節約する価値はありません。
ロボット

3
もう1つの重要な特性:埋め込まれたゼロコードポイントがない場合、文字列には埋め込まれたゼロはありません。
デデュプリケーター

タイ語のスクリプトの場合、印刷文字ごとに4バイトを許可する必要があります。彼らはパーティーに遅れて来ただけでなく、多数のコードグループを獲得しました。印刷時に単一の文字のように見えるものの多くは、実際には3つの異なるUnicode文字で構成されています。
ジェームズアンダーソン

@ qbt937:スキームを使用して、ある文字列に別の文字列が含まれているかどうかを調べるために、どのようにすばやくスキャンしますか?
supercat

6

公式の方法では、デコーダーがタプルの中央にあることを認識し、バイトが0orで始まるまでバイトをスキップする(または逆方向に進む)ことを認識します11。これにより、1バイトが破損した場合にガベージ値が防止されます。


3

短い答え、あなたの提案は最初のバイトと継続バイトを区別しません。

最初のバイトの上端のビットパターンは、実際の文字が何バイト構築されているかを示します。これらのパターンは、文字列の解析中にエラー認識も提供します。(一見)文字の最初のバイトを読んでいて、10xxxxxxを取得した場合、同期していないことがわかります。


2

言及されていないのは、コードポイントの正しいシーケンスと、コードポイントの最初のバイトを指すことが保証されているポインターがある場合、UTF-8では最初のバイトへのポインターを非常に簡単に見つけることができるということです前のコードポイントの(01xx xxxxで始まるすべてのバイトをスキップします)。エンコードを使用すると、文字列の先頭までのすべてのバイトを潜在的に調べることなく不可能です。

(2n + 2)バイトのシーケンスを考えます

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

そして

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

このシーケンスの後に最初のコードポイントの最初のバイトへのポインターがある場合、すべてのバイトを調べて、最後のコードポイントが0xxxxxxxまたは(10xxxxxx、0xxxxxxx)かどうかを調べる必要があります。

実際には、より効率的なエンコードスキームがあり、前のコードポイントへの移動を一定の時間で実行でき、コードポイントの中央へのポインターを修正できます。次のコードを許可します。

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

前の3バイトのいずれかが236以上の場合、有効な3バイトシーケンス内にそのようなバイトが2つあることはないため、3バイトシーケンスの開始です。それ以外の場合、前の2バイトのいずれかが≥128の場合、2バイトシーケンスの開始です。それ以外の場合、前のバイトは単一バイト<128です。

部分文字列の検索は少し難しくなります。文字列にゼロコードポイントが含まれる場合にのみゼロバイトが含まれるように、ゼロバイトを除外することができます。


言及されていないこと… – @ratchet freakの回答で行われた観察から直接これが実際に続くわけではありません。
ピョートルドブロゴスト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.