web-dev-qa-db-ja.com

CSVファイルから変数への値の読み取り

最大100エントリのCSVファイルから構造体の配列に値を読み取るための簡単なコードを記述しようとしています。

CSVファイルの行の例:

1、Mr、James、Quigley、Director、200000,0

次のコードを使用して値を読み込みますが、値を出力すると正しくありません

for(i = 0; i < 3; i++) /*just assuming number of entries here to demonstrate problem*/
    {
    fscanf(f, "%d,%s,%s,%s,%s,%d,%d", &inArray[i].ID, inArray[i].salutation, inArray[i].firstName, inArray[i].surName, inArray[i].position, &inArray[i].sal, &inArray[i].deleted);
    } 

次に、名を印刷すると、値はすべて名に割り当てられます。

for(j = 0; j < 3; j++) /* test by printing values*/
    {
    printf("Employee name is %s\n", inArray[j].firstName);
    } 

与えるames,Quigley,Director,200000,0など。それが私がfscanf行をフォーマットする方法であると確信していますが、それを機能させることができません。

これが私が読んでいる私の構造体です:

typedef struct Employee
    {
    int ID;
    char salutation[4];
    char firstName[21];
    char surName[31];
    char position[16];
    int sal;
    int deleted;
    } Employee;
8
Dawson

これは、文字列_%s_にカンマを含めることができるため、最初の文字列にスキャンされるためです。 scanf()フォーマット指定子には「先読み」はありません。フォーマット指定文字列で_%s_の後にコンマが続くという事実は何の意味もありません。

文字グループを使用する(検索 マニュアル for [)。

_const int got = fscanf(f, "%d,%[^,],%[^,],%[^,],%[^,],%d,%d", &inArray[i].ID,
                       inArray[i].salutation, inArray[i].firstName,
                       inArray[i].surName, inArray[i].position, &inArray[i].sal, 
                       &inArray[i].deleted);
_

そして、I/O呼び出しが失敗する可能性があるため、戻り値を確認することを学びます! gotが7でない限り、有効なデータに依存しないでください。

プログラムにファイル全体(複数のレコード、つまり行)を読み取らせるには、行全体をfgets()を使用して(大きな)固定サイズのバッファーにロードしてから、sscanf()を使用することをお勧めします。そのバッファは、列の値を解析します。これははるかに簡単で、実際に別々の行をスキャンすることを保証します。ループでfscanf()を呼び出すと、fscanf()への改行は空白であるため、スキャンされません。

17
unwind

答えとして私のコメントを投稿することもできます:

%sはデフォルトで完全なWordを読み取ります。

整数部分である%d、次に,を見つけ、文字列を読み取る必要があります。 ,はWordで有効と見なされるため(空白ではありません)、最初のコンマまでではなく、行の終わりまで読み取ります(それまで空白はありません)...そして残りは空のままです。 (この回答から)

正規表現を指定してセパレータを変更する必要があります。

fscanf(f, "%d,%[^,],%[^,],%[^,],%[^,],%d,%d", &inArray[i].ID, inArray[i].salutation, inArray[i].firstName, inArray[i].surName, inArray[i].position, &inArray[i].sal, &inArray[i].deleted);

%sの代わりに%[^,]を使用します。これは、「すべての文字を取得し、,が見つかったら停止する」ことを意味します。

[〜#〜]編集[〜#〜]

%[^,]sは悪いです、スキャンセットの終了後にリテラルsが必要になります...ありがとう@MichaelPotter

scanf()区切り文字の変更 および CSVファイルから変数への値の読み取り から)

2
ppeterka