2017-11-18 20 views
0

次のCコードはstdinからfgetws()を使用して行を読み取り、stdoutに書き込みます。fgetws()とUTF-8を使用したEILSEQ

#include <stdio.h> 
#include <locale.h> 
#include <wchar.h> 

#define STR_LEN 128 

int main(int argc, char **argv) 
{ 
    FILE *infile = stdin, *outfile = stdout; 
    wchar_t str[STR_LEN]; 

    if (setlocale(LC_ALL, "en.UTF-8") == NULL) { 
     fprintf(stderr, "Cannot set locale\n"); 
     return 1; 
    } 


    for (;;) { 

     if (!fgetws(str, STR_LEN, infile)) { 
      if (feof(infile)) { 
       break; 
      } 
      perror("fgetws()"); 
      continue; 
     } 
     str[wcscspn(str, L"\r\n")] = L'\0'; 

     if (fwprintf(outfile, L"%ls\n", str) < 0) { 
      perror("fwprintf()"); 
     } 

    } 

    return 0; 
} 

それは、常にASCIIファイルと完璧に動作しますが、UTF-8のデータを読み込むときに、時にはそれがfgetws()からEILSEQエラー(不正なバイト列)を取得し、私はその理由を把握することはできません。

出力ファイルで、エラーの原因となった行が切り捨てられ、いくつかの文字が欠落し、残りの部分が次の行にあります。 奇妙なことは、私がその行だけを与えると、私はエラーを起こさないということです。

たとえば、わずか数行のUTF-8回線でファイルを読み込んだ場合は問題ありません。同じ行を何回も繰り返すと、私はEILSEQになります。

私は、ファイルが正しくエンコードされていると確信しています。

私はmusl-libcでLinuxを使用しています。

私のコードで何が間違っていますか?

EDIT: は、私は、入力サイズに応じて、いくつかのEILSEQエラーが出ますが、私は2つのbeetween正確な関係を知りません。

同じ入力では、同じ行で同じエラーが発生します。

エラーを引き起こす特定のオフセットまたは文字ではないようですが、間違っている可能性があります。

EDIT 2: 私はこのコードをOpenBSDでもテストしています。この時点で、私はこの問題がLinuxやmusl-libcに関係していると考えています。

+0

'STR = 0;'かもしれませんより良い方法。 – wildplasser

+0

確かに。ありがとうございました。 –

+0

ファイルの同じポイントで常に失敗しますか? EILSEQの1つまたは2つのエラーが発生しますか?エラーを引き起こす文字の正確なバイトオフセットとその文字のutf-8コードは何ですか? – rici

答えて

0

UTF-8は文字を格納するためにcharを使用しますが、ANSIと同じ方法で動作します。唯一の違いは、言語文字が1文字より長くなることです。

wchar_t WindowsのUTF-16ではワイド文字列関数が使用されています。 Linuxでは、char16_tを使用してUTF-16を保管しますが、UTF-16ファイルを使用している場合に限ります。それは明らかにここでは当てはまりません。

ただ、UTF-8、あなたはANSIで作業まったく同じ方法で処理するためにchar機能を使用します。[(STR、 "\ rを\ n" は)strcspn]

char str[STR_LEN]; 
while(fgets(str, STR_LEN, infile)) 
{ 
    str[strcspn(str, "\r\n")]; 
    fprintf(outfile, "%s\n", str); 
} 
+0

はい、上記のプログラムは 'char'文字列でも動作します。しかし、読んだ後に1文字を操作する必要があれば、 'wchar_t'が必要でしょうか?私は外部ライブラリ(ICUなど)を使用しない方が好きです。なぜなら、単純なことしかしないからです。 –

+0

Linuxを使用していませんか? 'whcar_t'はWindowsで使われていますが、Linuxではほとんど使われません。ちょうど 'char'を使用してください。 ''\ n' 'や''、 ''のようなANSI文字を探しているだけであれば、テキストを解析することができます。なぜならそれらの文字は他の場所で繰り返されないからです。通常のANSIテキストとして扱います。しかし、 "ελληνικά"のようなものがあれば、 "η"は異なる文字の組み合わせであるため、そのオプションを必要とすることはほとんどありません。 –

+0

残念ながら、非ASCII文字で操作を実行する必要があります。 –

関連する問題