1. ホーム
  2. c++

[解決済み] C++11での文字列リテラルのUnicodeエンコーディング

2023-05-01 10:44:39

質問

に続いて 関連する質問 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 エンコードと型機能に関する可能な限り完全な画像を取得したいと思います。

どのように解決するのですか?

文字参照は、すべての文字列型と自由に組み合わせられますか?

いいえ。 \x は何にでも使えますが \u\U は、特にUTFエンコードされた文字列でのみ使用することができます。しかし、どんなUTFエンコードされた文字列に対しても \u\U は適当に使ってください。

<ブロッククオート

文字列型はすべて固定幅で、リテラルと同じ数の要素を含む配列ですか?

その通りではありません。 \x , \u そして \U は、文字列のエンコーディングに基づいて変換されます。その数は、quot;code units"(Unicodeの用語を使用。A char16_t はUTF-16のコードユニット)値の数は、含む文字列のエンコーディングに依存します。リテラル u8"\u1024" と書くと、2つの char とヌルターミネータを含む文字列を作成します。リテラル u"\u1024" を含む文字列が作成されます。 char16_t とヌルターミネータを含む文字列を作成します。

使用されるコードユニットの数は、Unicodeのエンコーディングに基づきます。

例えば、char16_t x[] = u"\U0010FFFF" と言うと、非BMPコードポイントは2単位のUTF16シーケンスにエンコードされますか?

u"" はUTF-16でエンコードされた文字列を生成します。 u8"" はUTF-8でエンコードされた文字列を生成します。これらは、Unicodeの仕様に従ってエンコードされます。

(1)で、lone surrogatesを "su "と書いてもいいのでしょうか?

絶対にダメです。仕様では、UTF-16のサロゲートペア(0xD800-0xDFFF)を \u または \U .

最後に、文字列関数のうち、エンコーディングを意識したものはありますか(つまり、文字を意識し、無効なバイト列を検出できるもの)?

絶対にありません。そうですね、言い直させてください。

std::basic_string はUnicodeエンコーディングを扱わない。それらは確かに ストア UTF エンコードされた文字列を格納することができます。しかし、彼らはそれらを char , char16_t または char32_t というように、特定のメカニズムでエンコードされた Unicode コードポイントのシーケンスとして考えることができないのです。 basic_string::length() はコードポイントの数ではなく、コードユニットの数を返します。そして明らかに、C 標準ライブラリの文字列関数はまったく役に立ちません。

しかし、Unicode 文字列の "length" は、コードポイントの数を意味しないことに注意する必要があります。いくつかのコードポイントは、quot;character" (残念な名前です) を結合しており、前のコードポイントに結合されます。そのため、複数のコードポイントが1つの視覚的な文字に対応することができます。

Iostreams は実際、Unicode でエンコードされた値を読み書きすることができます。これを行うには、ロケールを使用してエンコードを指定し、それをさまざまな場所に適切に埋め込む必要があります。これは言うは易く行うは難しで、私はその方法を示すためのコードを持ち合わせていません。