web-dev-qa-db-ja.com

C ++ 11の文字列リテラルのUnicodeエンコーディング

関連する質問 に続いて、C++ 11の新しい文字および文字列リテラルタイプについてお聞きしたいと思います。現在、4種類の文字と5種類の文字列リテラルがあるようです。文字タイプ:

char     a =  '\x30';         // character, no semantics
wchar_t  b = L'\xFFEF';       // wide character, no semantics
char16_t c = u'\u00F6';       // 16-bit, assumed UTF16?
char32_t d = U'\U0010FFFF';   // 32-bit, assumed UCS-4

そして、文字列リテラル:

char     A[] =  "Hello\x0A";         // byte string, "narrow encoding"
wchar_t  B[] = L"Hell\xF6\x0A";      // wide string, impl-def'd encoding
char16_t C[] = u"Hell\u00F6";        // (1)
char32_t D[] = U"Hell\U000000F6\U0010FFFF"; // (2)
auto     E[] = u8"\u00F6\U0010FFFF"; // (3)

質問はこれです:\x/\u/\U文字参照は、すべての文字列型と自由に組み合わせることができますか?すべての文字列型は固定幅です。つまり、配列にはリテラルに表示される要素と正確に同じ数の要素が含まれますか、または\x/\u/\U参照は可変数に展開されますバイト? u""およびu8""文字列にはエンコードセマンティクスがありますか。 char16_t x[] = u"\U0010FFFF"と言えば、非BMPコードポイントは2ユニットのUTF16シーケンスにエンコードされますか? u8についても同様です。 (1)で、\uを使用して孤独なサロゲートを記述できますか?最後に、文字列関数のエンコーディングは認識されていますか?

これはちょっとした自由回答形式の質問ですが、新しいC++ 11の新しいUTFエンコーディングと型の機能について可能な限り完全に把握したいと思います。

76
Kerrek SB

\ x/\ u/\ U文字参照は、すべての文字列型と自由に組み合わせることができますか?

いいえ。_\x_は何でも使用できますが、_\u_および_\U_は、特にUTFエンコードされた文字列でのみ使用できます。ただし、UTFエンコードされた文字列の場合、_\u_および_\U_を適切に使用できます。

すべての文字列型は固定幅です、つまり、配列にはリテラルに表示される要素が正確に含まれていますか、または\ x/\ u/\ Uへの参照は可変バイト数に展開されますか?

あなたが意味する方法ではありません。 _\x_、_\u_、および_\U_は、文字列エンコードに基づいて変換されます。これらの「コード単位」(Unicodeの用語を使用。A_char16_t_はUTF-16コード単位)の値の数は、含まれる文字列のエンコードに依存します。リテラル_u8"\u1024"_は、2つのcharsとヌルターミネータを含む文字列を作成します。リテラル_u"\u1024"_は、1 _char16_t_に加えてヌルターミネータを含む文字列を作成します。

使用されるコード単位の数は、Unicodeエンコードに基づいています。

U ""とu8 ""の文字列にはエンコードセマンティクスがありますか。 char16_t x [] = u "\ U0010FFFF"と言えば、非BMPコードポイントは2ユニットのUTF16シーケンスにエンコードされますか?

_u""_は、UTF-16エンコード文字列を作成します。 _u8""_はUTF-8エンコードされた文字列を作成します。それらはUnicode仕様に従ってエンコードされます。

(1)で、\ uを使用して単独のサロゲートを記述できますか?

絶対違う。仕様では、UTF-16サロゲートペア(0xD800-0xDFFF)を_\u_または_\U_のコードポイントとして使用することを明示的に禁止しています。

最後に、文字列関数のエンコーディングは認識されていますか?

絶対違う。さて、それを言い換えさせてください。

_std::basic_string_はUnicodeエンコーディングを処理しません。確かにstore UTFエンコードされた文字列です。しかし、それらはchar、_char16_t_、または_char32_t_のシーケンスとしてしか考えることができません。特定のメカニズムでエンコードされたUnicodeコードポイントのシーケンスと考えることはできません。 basic_string::length()は、コードポイントではなくコード単位の数を返します。そして、明らかに、C標準ライブラリの文字列関数はまったく役に立ちません

ただし、Unicode文字列の「長さ」はコードポイントの数を意味しないことに注意してください。一部のコードポイントは、「文字」(不幸な名前)を組み合わせており、以前のコードポイントと組み合わせています。したがって、複数のコードポイントを単一の視覚的キャラクターにマッピングできます。

実際、IostreamはUnicodeエンコード値を読み書きできます。そのためには、ロケールを使用してエンコードを指定し、それをさまざまな場所に適切に埋め込む必要があります。これは言うよりも簡単であり、その方法を示すコードはありません。

51
Nicol Bolas