4

私は、文字ごとにUTF-8要素を含むファイルを読み取る小さなプログラムを作成中です。文字を読み取った後、それを他のいくつかの文字と比較し、一致する場合は、ファイル内の文字をアンダースコア「_」に置き換えます。

(実際には、特定の文字がアンダースコアに置き換えられたファイルの複製が作成されます。)

ここでどこを台無しにしているのか正確にはわかりませんが、どこにでもある可能性が高いです。

これが私のコードです:

   FILE *fpi;
   FILE *fpo;
   char ifilename[FILENAME_MAX];
   char ofilename[FILENAME_MAX];
   wint_t sample;


   fpi = fopen(ifilename, "rb");
   fpo = fopen(ofilename, "wb");

   while (!feof(fpi)) {
     fread(&sample, sizeof(wchar_t*), 1, fpi);

     if ((wcscmp(L"ά", &sample) == 0) || (wcscmp(L"ε", &sample) == 0)  ) {
   fwrite(L"_", sizeof(wchar_t*), 1, fpo);

     } else {
       fwrite(&sample, sizeof(wchar_t*), 1, fpo);

     }
   } 

ファイル名の生成に関係するコードは省略しました。ケースに提供するものがないためです。単なる文字列操作です。

このプログラムに単語を含むファイルをフィードすると、次のγειά σου κόσμε.ように返されます。 γει_ σου κόσμ_.

ほとんどの結果は非常に一般的であるか、UTF-8 に関してまったく異なることについて話しているため、インターネットを検索してもあまり役に立ちませんでした。なんらかの理由で、誰も単一の文字を操作する必要がないようです。

私を正しい方向に向けてくれるものは何でも大歓迎です。必ずしも、提出したコードの単純な修正バージョンを探しているわけではありません。wchar メカニズムが正確にどのように機能するかを理解するのに役立つ洞察に満ちたコメントに感謝します。全体の wbyte、wchar、L、no-L は、私にとって混乱です。

よろしくお願いいたします。

4

2 に答える 2

6

C には、マルチバイト文字ワイド文字の 2 種類の文字があります。

マルチバイト文字は、さまざまなバイト数を取ることができます。たとえば、UTF-8 ( Unicodeの可変長エンコーディングa) では、 1 バイトがα必要ですが、2 バイトが必要です。

ワイド文字は常に同じバイト数を取ります。さらに、 awchar_tは実行文字セットの任意の 1 文字を保持できる必要があります。したがって、UTF-32 を使用する場合、 と の両方aαそれぞれ 4 バイトかかります。残念ながら、一部のプラットフォームはwchar_t16 ビット幅にしました。そのようなプラットフォームでは、wchar_t. __STDC_ISO_10646__が定義されている場合、 wchar_tUnicode コードポイントを保持するため、(少なくとも) 4 バイトの長さでなければなりません (技術的には、少なくとも 21 ビットの長さでなければなりません)。

そのため、UTF-8 を使用する場合は、通常の変数に格納されているマルチバイト文字を使用する必要があります (ただし、マルチバイト文字ではなくバイトをカウントする にchar注意してください)。strlen()

残念ながら、Unicode にはこれ以上のものがあります。

ά単一の Unicode コードポイントとして、または 2 つの別個のコードポイントとして表すことができます。

  • U+03AC GREEK SMALL LETTER ALPHA WITH TONOS← 1 コードポイント ← 1 マルチバイト文字 ← 2 バイト ( 0xCE 0xAC) = 2charの。
  • U+03B1 GREEK SMALL LETTER ALPHA U+0301 COMBINING ACUTE ACCENT← 2 コードポイント ← 2 マルチバイト文字 ← 4 バイト ( 0xCE 0xB1 0xCC 0x81) = 4charです。
  • U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA← 1 コードポイント ← 1 マルチバイト文字 ← 3 バイト ( 0xE1 0xBD 0xB1) = 3charです。

上記はすべて標準的な等価物であり、すべての目的で同等に扱われるべきであることを意味します。そのため、Unicode 正規化アルゴリズムの 1 つ (NFC、NFD、NFKC、NFKD の 4 つ) を使用して、入力/出力で文字列を正規化する必要があります。

于 2012-09-07T19:13:58.093 に答える
3

まず、UTF8とUnicode、および文字列とエンコーディングに関するその他の重要な事項について説明しているこのすばらしい記事をお読みください。http: //www.joelonsoftware.com/articles/Unicode.html

コードで実行しようとしていることは、Unicodeで文字ごとに読み取られ、それらと比較されます。入力ストリームがUTF8の場合、これは機能しません。また、この構造では実際には不可能です。

つまり、完全なUnicode文字列はいくつかの方法でエンコードできます。それらの1つは、各文字に1つずつ、同じサイズの一連の「ワイド」文字を使用しています。それがwchar_tタイプ(時にはWCHAR)の目的です。もう1つの方法はUTF8です。これは、文字の値に応じて、可変数のrawバイトを使用して各文字をエンコードします。

UTF8は単なるバイトのストリームであり、Unicode文字列をエンコードでき、ファイルで一般的に使用されます。これは、より一般的なメモリ内表現であるWCHARの文字列と同じではありません。UTF8ストリームを確実に突き抜けて、その中で文字を直接置き換えることはできません。すべてを読み込んでデコードし、結果のWCHARをループして比較と置換を行い、その結果をUTF8にマップして出力ファイルに書き込む必要があります。

Win32では、MultiByteToWideCharを使用してデコードを実行し、対応するWideCharToMultiByteを使用して戻ることができます。

通常の引用符でを使用すると、Unicodeをサポートしない"string literal"ヌル文字で終了するASCII文字列()が作成されます。プレフィックス付きのはchar*、文字列または文字の比較に使用できるWCHARのヌル終了文字列(wchar_t *)を作成します。Lプレフィックスは、次のように一重引用符の文字リテラルでも機能します。L"string literal"LL'ε'


コメント提供者が指摘したように、fread / fwriteを使用するときはsizeof(wchar_t)、ポインターの種類ではなく使用する必要があります。読み取り/書き込みしようとしている量は実際のwcharであり、ポインターのサイズではないためです。このアドバイスは、上記とは関係のない単なるコードフィードバックです。とにかく、入力文字を1文字ずつ読みたくないでしょう。

文字列の比較(wcscmp)を行うときは、実際のワイド文字列(nul wide charで終了)を使用する必要があることにも注意してください。メモリ内の単一文字を入力として使用しないでください。文字間の比較を行う場合(いつ)、文字列関数を使用する必要はありません。WCHARは単なる値であるため、直接比較できますif (sample == L'ά') {}

于 2012-09-07T18:10:55.160 に答える