UTF-16は固定幅ですか、可変幅ですか?UTF-8にバイト順の問題がないのはなぜですか?


16
  1. UTF-16は固定幅ですか、可変幅ですか?さまざまなソースからさまざまな結果が得られました。

    http://www.tbray.org/ongoing/When/200x/2003/04/26/UTFから:

    UTF-16は、Unicode文字を16ビットのチャンクに格納します。

    http://en.wikipedia.org/wiki/UTF-16/UCS-2から:

    UTF-16(16ビットUnicode変換フォーマット)は、0〜0x10FFFFのUnicodeコードスペースで1,112,064 [1]数(コードポイントと呼ばれる)をエンコードできるUnicodeの文字エンコードです。コードポイントごとに1つまたは2つの16ビットコード単位の可変長の結果を生成します。

  2. 最初のソースから

    UTF-8には、エンコードの単位がバイトであるという利点もあるため、バイト順序の問題はありません。

    UTF-8にバイト順の問題がないのはなぜですか?可変幅であり、1文字に複数のバイトが含まれている可能性があるため、バイトオーダーが依然として問題になると思いますか?

よろしくお願いします!


回答:


13

(1)バイトシーケンスとはどういう意味ですか?UTF-16はバイトシーケンスですか、それとも何ですか?(2)なぜバイトシーケンスが可変長とは関係ないのですか?

エンディアンの問題を誤解しているようです。ここに簡単な要約があります。

32ビット整数は4バイトを占有します。これで、これらのバイトの論理的な順序がわかりました。32ビット整数がある場合、次のコードでこれの上位バイトを取得できます。

uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81

それはすべてうまくいっています。問題が始まるのは、さまざまなハードウェアがどのように整数をメモリから保存および取得するかです。

ビッグエンディアン順では、32ビット整数として読み取る4バイトのメモリは、最初のバイトが上位バイトで読み取られます。

[0][1][2][3]

リトルエンディアンの順序では、32ビット整数として読み取る4バイトのメモリは、最初のバイトが下位バイトで読み取られます。

[3][2][1][0]

32ビット値へのポインターへのポインターがある場合、これを行うことができます。

uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?

C / C ++によると、この結果は未定義です。0x81の可能性があります。または、0x32である可能性があります。技術的には、何でも返すことができますが、実際のシステムでは、どちらか一方を返します。

メモリアドレスへのポインタがある場合、そのアドレスを32ビット値、16ビット値、または8ビット値として読み取ることができます。ビッグエンディアンマシンでは、ポインターは上位バイトを指します。リトルエンディアンのマシンでは、ポインターは下位バイトを指します。

これは、メモリの読み取りと書き込みに関するものであることに注意してください。内部C / C ++コードとは関係ありません。C / C ++が未定義として宣言しないコードの最初のバージョンは、常に上位バイトを取得するために機能します。

問題は、バイトストリームの読み取りを開始するときです。ファイルからなど。

16ビット値には、32ビット値と同じ問題があります。4バイトではなく2バイトだけです。したがって、ファイルにはビッグエンディアンまたはリトルエンディアンの順序で格納された16ビット値を含めることができます。

UTF-16は16ビット値のシーケンスとして定義されます。事実上、それはuint16_t[]です。各コード単位は16ビット値です。したがって、UTF-16を適切にロードするには、データのエンディアンが何であるかを知る必要があります。

UTF-8は、8ビット値のシーケンスとして定義されます。それはuint8_t[]です。個々のコード単位は、サイズが8ビット(1バイト)です。

現在、UTF-16とUTF-8の両方で、複数のコードユニット(16ビットまたは8ビット値)を組み合わせてUnicodeコードポイント(「文字」ですが、これは正しい用語ではありません。これは簡略化です) )。コードポイントを形成するこれらのコードユニットの順序は、UTF-16およびUTF-8エンコーディングによって決まります。

UTF-16を処理する場合、16ビット値を読み取り、必要なエンディアン変換を実行します。次に、サロゲートペアかどうかを検出します。そうである場合は、別の16ビット値を読み取り、2つを組み合わせて、そこからUnicodeコードポイント値を取得します。

UTF-8を処理するとき、8ビット値を読み取ります。1バイトしかないため、エンディアン変換はできません。最初のバイトがマルチバイトシーケンスを示す場合、マルチバイトシーケンスの指示に従って、いくつかのバイトを読み取ります。個々のバイトは1バイトであるため、エンディアン変換は行われません。オーダーだけUTF-16サロゲートペアの順序と配列中のこれらのバイトは、UTF-8で定義されています。

したがって、UTF-8にはエンディアンの問題はありません。


10

ジェレミー・バンクスの答えは正しい限りですが、バイトの順序付けについては言及していません。

UTF-16を使用する場合、ほとんどのグリフは2バイトの単語を使用して保存されますが、単語がディスクファイルに保存される場合、構成バイトの保存にはどの順序を使用しますか?

例として、「water」という単語のCJK(中国語)グリフには、6C34の16進数のUTF-16エンコードがあります。これをディスクに2バイトとして書き込む場合、「ビッグエンディアン」として書き込みますか(2バイトは6C 34です)?または、「リトルエンディアン(2バイトは34 6C)」と記述しますか?

UTF-16では、両方の順序が正当であり、通常、ファイル内の最初の単語をバイトオーダーマーク(BOM)にすることでファイルのどちらかを示します。エンコードはFF FEです。

UTF-32にも同じ問題と同じ解決策があります。

UTF-8は可変長であり、グリフのバイトシーケンスをリトルエンディアンであるかのように効果的に記述するため、この問題はありません。たとえば、文字「P」は常に1バイト-80-を使用してエンコードされ、置換文字は常に2バイトのFF FDをこの順序で使用してエンコードされます。

一部のプログラムでは、UTF-8ファイルの先頭に3バイトのインジケーター(EF BB BF)を配置します。これにより、UTF-8とASCIIなどの類似のエンコードを区別できますが、MS Windows以外ではあまり一般的ではありません。


ありがとう!(1)文字「P」はUTF-8の1バイトです。置換文字がコードに追加されるのはなぜですか?(2)UTF-8には、UTF-8に複数のバイトを持つ他の文字があります。そのような各文字のバイト間のバイト順が問題にならないのはなぜですか?
ティム

@Tim:(1)Pのコードに置換文字を追加しません。80FF FDが表示される場合、P文字と置換文字の2つの文字です。
ボブマーフィー

(2)常に、「置換文字」の2バイトをFF FDとしてこの順序で読み書きします。「置換文字」もFD FFとして記述できる場合にのみ、バイト順序の問題が発生しますが、できません。この2バイトのシーケンスは、「置換文字」以外のものです。
ボブマーフィー

1
@Tim:en.wikipedia.org/wiki/UTF-8で作業することをお勧めします。それは本当にかなり良いです、そしてあなたがそれのすべてと他のユニコード関連のウィキペディアのページを理解することができれば、私はあなたがそれについてもうこれ以上質問がないと思うと思います。
ボブマーフィー

4
UTF-8にバイトオーダーに関する問題がないのは、エンコーディングがバイトシーケンスとして定義されており、エンディアンが異なるバリエーションがないためです。可変長とは関係ありません。
スターブルー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.