14

すべての言語のテキストを処理できるようにする必要があるプログラムを作成しています。私の理解では、UTF-8 が機能するということですが、いくつか問題が発生しています。

UTF-8 は単純なcharC++ に格納できると言うのは正しいでしょうか? charもしそうなら、 、stringstringstream:でプログラムを使用すると、なぜ次の警告が表示されるのですかwarning C4566: character represented by universal-character-name '\uFFFD' cannot be represented in the current code page (1252)? wchar_t( 、 、wstringおよびを使用すると、そのエラーは発生しませんwstringstream。)

さらに、UTF は可変長であることも知っています。atまたはstring メソッドを使用するsubstrと、間違った答えが得られますか?

4

3 に答える 3

18

UTF-8文字列リテラルを使用するには、接頭辞を付ける必要がありますu8。そうしないと、実装の文字セットが取得されます(この場合、Windows-1252のようです):u8"\uFFFD"は、UTF-8表現のnullで終了するバイトシーケンスです。置換文字(U + FFFD)。タイプがありchar const[4]ます。

UTF-8の長さは可変であるため、すべての種類のインデックス作成は、コードポイントではなくコード単位でインデックス作成を行います。UTF-8シーケンスは可変長であるため、コードポイントにランダムアクセスすることはできません。ランダムアクセスが必要な場合は、UTF-32などの固定長エンコーディングを使用する必要があります。そのためにはU、文字列にプレフィックスを使用できます。

于 2012-08-20T15:29:02.223 に答える
11

はい、UTF-8 エンコーディングは、char、string、および stringstream で使用できます。char は単一の UTF-8 コード単位を保持します。単一の Unicode コード ポイントを表すには、最大 4 つが必要になる場合があります。

ただし、特に Microsoft のコンパイラで UTF-8 を使用する場合、いくつかの問題があります。C++ 実装では、文字や文字列リテラルのエンコードなど、多くの目的で「実行文字セット」を使用します。VC++ は常にシステム ロケール エンコーディングを実行文字セットとして使用し、Windows はシステム ロケール エンコーディングとして UTF-8 をサポートしていないため、実行文字セットによって UTF-8 を使用することはできません。

これは、VC++ が意図的に UTF-8 文字および文字列リテラルを生成しないことを意味します。代わりに、コンパイラをだます必要があります。

コンパイラは、既知のソース コード エンコーディングから実行エンコーディングに変換します。つまり、コンパイラがソース エンコーディングと実行エンコーディングの両方にロケール エンコーディングを使用する場合、変換は行われません。UTF-8 データをソース コードに取り込めるが、ソースがロケール エンコーディングを使用しているとコンパイラに認識させる場合、文字および文字列リテラルは UTF-8 エンコーディングを使用します。VC++ はいわゆる「BOM」を使用してソース エンコーディングを検出し、BOM が検出されない場合はロケール エンコーディングを使用します。したがって、すべてのソース ファイルを「署名なしの UTF-8」として保存することで、UTF-8 でエンコードされた文字列リテラルを取得できます。

この方法には注意点があります。まず、狭い文字と文字列リテラルで UCN を使用することはできません。Universal Character Names は、UTF-8 ではない実行文字セットに変換する必要があります。ソース コードで UTF-8 として表示されるように文字を文字どおりに記述するか、16 進エスケープを使用して UTF-8 エンコーディングを手動で書き出す必要があります。次に、ワイド文字と文字列リテラルを生成するために、コンパイラはソース エンコーディングからワイド実行文字セット (VC++ では常に UTF-16) への同様の変換を実行します。エンコーディングについてコンパイラに嘘をついているので、この UTF-16 への変換は正しく行われません。したがって、ワイド文字および文字列リテラルでは、ASCII 以外の文字をそのまま使用することはできず、代わりに UCN または 16 進エスケープを使用する必要があります。


UTF-8 は可変長です (UTF-16 と同様)。at()およびで使用されるインデックスは、文字インデックスまたはコード ポイント インデックスでsubstr()はなく、コード単位です。したがって、特定のコード単位が必要な場合は、通常どおり文字列または配列などにインデックスを付けることができます。特定のコード ポイントが必要な場合は、UTF-8 コード単位をコード ポイントに構成することを理解できるライブラリ (Boost Unicode イテレータ ライブラリなど) が必要か、UTF-8 データを UTF-32 に変換する必要があります。実際のユーザーが認識する文字が必要な場合は、コード ポイントがどのように文字に構成されるかを理解するライブラリが必要です。ICU にはそのような機能があると思います。または、Unicode 標準からDefault Grapheme Cluster Boundary Specificationを実装することもできます。


上記の UTF-8 の考慮事項は、ソース コードで Unicode データをどのように記述するかについてのみ重要です。プログラムの入出力にはほとんど影響しません。

要件によって入力と出力の方法を選択できる場合でも、入力には UTF-8 を使用することをお勧めします。入力に対して何をする必要があるかに応じて、処理が簡単な別のエンコーディングに変換するか、UTF-8 で直接動作するように処理ルーチンを作成できます。

Windowsコンソール経由で何かを出力したい場合は、さまざまな実装を持つことができる出力用の明確に定義されたモジュールが必要です.Windowsコンソールへの国際化された出力には、Windowsまたはコンソール上のファイルへの出力とは異なる実装が必要になるためです.および他のプラットフォームでのファイル出力。(他のプラットフォームでは、コンソールは単なる別のファイルですが、Windows コンソールには特別な処理が必要です。)

于 2012-08-20T16:00:29.363 に答える
1

警告が表示される理由は、ご指摘のとおり、UTF-8 はs で機能し、可変長であるため、1 バイト\uFFFDに収まるようにしようとしているためです。FF FDchar

atまたはを使用するsubstrと、これらのメソッドは 1 バイトが 1 文字であるとカウントされるため、間違った答えが得られる可能性があります。これは UTF-8 には当てはまりません。特に、 を使用するとat、文字シーケンスの 1 バイトになる可能性があります。を使用するとsubstr、シーケンスが壊れて無効な UTF-8 文字列になる可能性があります (\uFFFD使用しようとしているのと同じ � で開始または終了し、壊れた文字が失われます)。

wcharUnicode 文字列を格納するために使用することをお勧めします。タイプは少なくとも 16 ビットであるため、さらに多くの文字を 1 つの「ユニット」に収めることができます。

于 2012-08-20T15:28:28.253 に答える