web-dev-qa-db-ja.com

C ++のUTF-8でstd :: stringを適切に使用するにはどうすればよいですか?

私のプラットフォームはMacとC++ 11(またはそれ以上)です。私はC++初心者で、中国語と英語を処理する個人プロジェクトに取り組んでいます。 UTF-8は、このプロジェクトの推奨エンコーディングです。

Stack Overflowに関するいくつかの投稿を読みましたが、それらの多くはUTF-8を扱うときにstd::stringを使用することを提案し、現在UTF-8にはwchar_tがないのでchar8_tを避けます。

ただし、str[i]std::string::size()std::string::find_first_of()、またはstd::regexなどの関数を適切に処理する方法については、UTF-8に直面したときにこれらの関数が通常予期しない結果を返すため、これらについては話しません。

std::stringを続行するか、std::wstringに切り替える必要がありますか? std::stringのままにする必要がある場合、上記の問題を処理するためのベストプラクティスは何ですか?

55
stackunderflow

std::stringstd::wstringは両方とも、UTFエンコードを使用してUnicodeを表す必要があります。特にmacOSでは、std::stringはUTF-8(8ビットコード単位)であり、std::wstringはUTF-32(32ビットコード単位)です。 wchar_tのサイズはプラットフォームに依存することに注意してください。

両方について、sizeは、コードポイントまたは書記素クラスターの数ではなく、コード単位の数を追跡します。 (コードポイントはUnicodeエンティティという名前の1つで、そのうちの1つ以上が書記素クラスタを形成します。書記素クラスタは、文字や絵文字など、ユーザーが対話する目に見える文字です。)

私は中国語のUnicode表現に精通していませんが、UTF-32を使用すると、コード単位の数が書記素クラスターの数に非常に近いことがよくあります。ただし、明らかに、これには最大4倍のメモリを使用するという犠牲が伴います。

最も正確な解決策は、ICUなどのUnicodeライブラリを使用して、求めているUnicodeプロパティを計算することです。

最後に、結合文字を使用しない人間の言語のUTF文字列は、通常find/regexで非常にうまく機能します。中国語についてはわかりませんが、英語もその1つです。

9
zneak

std::stringとその友達はエンコード非依存です。 std::wstringstd::stringの唯一の違いは、std::wstringcharではなくwchar_tを個々の要素として使用することです。ほとんどのコンパイラでは、後者は8ビットです。前者は、Unicode文字を保持するのに十分な大きさであると想定されていますが、一部のシステムでは実際にはそうではありません(たとえば、Microsoftのコンパイラは16ビットタイプを使用します)。 UTF-8をstd::wstringに保存することはできません。それは設計されたものではありません。 UTF-32(各要素が単一のUnicodeコードポイントである文字列)と同等になるように設計されています。

UTF-8文字列をUnicodeコードポイントまたは構成されたUnicodeグリフ(またはその他)でインデックス化する場合、Unicodeコードポイントまたは他のUnicodeオブジェクトでUTF-8文字列の長さをカウントするか、Unicodeコードポイントで検索します標準ライブラリ以外のものを使用する必要があります。 ICU は、フィールド内のライブラリの1つです。他にもあるかもしれません。

おそらく注目に値することは、ASCII文字を検索する場合、UTF-8バイトストリームをバイト単位で扱うことができるということです。各ASCII文字は、ASCIIの場合と同じUTF-8でエンコードし、UTF-8のすべてのマルチバイトユニットは、ASCII範囲のバイトを含まないことが保証されます。

8
James Picone

C++ 20とstd::u8stringにアップグレードすることを検討してください。これは、UTF-8を保持するための2019年時点での最良のものです。個々のコードポイントまたは書記素クラスタにアクセスするための標準ライブラリ機能はありませんが、少なくともあなたのタイプは、少なくともそれが本当のUTF-8であると言うほど十分に強力です。

2
Lyberta