[解決済み] C++でstd::stringをUTF-8で正しく使用するには?
質問
私のプラットフォームはMacです。私はC++初心者で、中国語と英語を処理する個人的なプロジェクトに取り組んでいます。このプロジェクトでは、UTF-8 が好ましいエンコーディングです。
私は Stack Overflow でいくつかの投稿を読みましたが、それらの多くは
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
を使用する場合、上記の問題を処理するための最良の方法は何でしょうか?
どのように解決するのですか?
ユニコード用語集
Unicodeは広大で複雑なトピックです。あまり深入りしたくないのですが、簡単な用語集は必要です。
- コードポイント : コードポイントは、Unicodeの基本的な構成要素であり、コードポイントは、単に整数を 意味 . 整数部は 32 ビット (実際には 24 ビット) に収まり、意味は文字、発音区分符号、空白、記号、スマイリー、半旗、...、さらには「次の部分は右から左へ読む」(quot; the next portion reads right to left") である可能性があります。
- 書記素クラスタ : Grapheme Clusters は意味的に関連したコードポイントのグループです。例えば、unicode の旗は 2 つのコードポイントを関連付けることで表現されています。Grapheme Cluster はまた、いくつかのスクリプトで文字と発音記号を組み合わせるために使用されます。
これはUnicodeの基本です。ほとんどの現代言語では、各文字は 1 つのコード ポイントにマップされるため、コード ポイントと書記素クラスタの区別はほとんど無視できます (よく使われる文字と発音記号の組み合わせには、専用のアクセント記号付きの形式があります)。それでも、スマイリーやフラグなどを使用する場合は、その区別に注意を払う必要があります。
UTF プライマー
一般的なエンコーディングはUTF-8、UTF-16、UTF-32で、後者2つはリトルエンディアンとビッグエンディアンの両方が存在し、合計5つの一般的なエンコーディングが存在します。
UTF-X では、X は コードユニット であり、各コードポイントはその大きさに応じて1つまたは複数のコードユニットとして表現されます。
- UTF-8:1~4個のコードユニット。
- UTF-16:1または2個のコードユニット。
- UTF-32。1つのコードユニット。
std::string
そして
std::wstring
.
-
を使用しないでください。
std::wstring
は使わないでください。wchar_t
は Windows では 16 ビットしかありません)。std::u32string
を使います (別名std::basic_string<char32_t>
). -
メモリ内表現(
std::string
またはstd::wstring
はディスク上の表現 (UTF-8、UTF-16、または UTF-32) に依存しないので、境界 (読み取りと書き込み) で変換する必要があることを覚悟しておいてください。) -
が 32 ビットであるのに対し
wchar_t
はコードユニットが完全なコードポイントを表すことを保証しますが、それでも完全な Grapheme Cluster を表すわけではありません。
文字列を読んだり作ったりするだけであれば
std::string
または
std::wstring
.
問題はスライスとダイシングを開始したときに始まり、(1) コードポイント境界 (UTF-8 または UTF-16) と (2) 書記素クラスタ境界 に注意を払う必要があります。前者は自分で簡単に処理できますが、後者は Unicode を認識するライブラリを使用する必要があります。
ピッキング
std::string
または
std::u32string
?
パフォーマンスが気になる場合は、おそらく
std::string
の方がメモリフットプリントが小さいため、より良いパフォーマンスを発揮すると思われます。ただし、中国語を多用する場合は契約が変更されるかもしれません。しかし、中国語を多用する場合は、その条件が変わるかもしれません。
Grapheme Clusters が問題でない場合は、次のようになります。
std::u32string
は、物事を単純化できる利点があります。1コードユニット -> 1コードポイントとは、誤ってコードポイントを分割してしまうことがないように、すべての機能が
std::basic_string
のすべての機能がそのまま機能します。
ソフトウェアテイクとのインターフェイスの場合
std::string
または
char*
/
char const*
であれば
std::string
を使うことで、前後の変換を避けることができます。そうしないと、面倒なことになります。
でのUTF-8
std::string
.
UTF-8 は実際には
std::string
.
UTF-8エンコーディングは自己同期しており、ASCIIとの後方互換性があるため、ほとんどの操作は箱から出してすぐに動作します。
コードポイントがエンコードされているため、コードポイントを探しても、他のコードポイントの途中と偶然に一致することはあり得ません。
-
str.find('\n')
が動作します。 -
str.find("...")
作品 バイト単位でのマッチングに 1 , -
str.find_first_of("\r\n")
作品 ASCII 文字を検索する場合 .
同様に
regex
はほとんどそのまま使えるはずです。一連の文字として (
"haha"
) は単なるバイトの列 (
"哈"
) であるため、基本的な検索パターンがそのまま使えるはずです。
しかし、文字クラス(例えば
[:alphanum:]
のような)文字クラスには注意が必要です。正規表現のフレーバーと実装によって、Unicode 文字にマッチする場合としない場合があります。
同様に、非 ASCII の "文字" にリピータを適用することに注意してください。
"哈?"
は最後のバイトだけをオプションとみなすかもしれません。そのような場合は、括弧を使って繰り返されるバイト列を明確に区別してください。
"(哈)?"
.
1
ルックアップのキーコンセプトは正規化と照合順序です。これはすべての比較操作に影響します。
std::string
は常にバイト単位で比較(そしてソート)し、言語や使用法に特有の比較ルールを気にすることはありません。完全な正規化/照合順序を処理する必要がある場合は、ICU のような完全な Unicode ライブラリが必要です。
関連
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] JavaでStringをintに変換するにはどうしたらいいですか?
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】大文字・小文字を区別しない「Contains(string)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】識別子 "string "は未定義?
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】C++の余分な資格エラー
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む