最大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;
これは、文字列_%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()
への改行は空白であるため、スキャンされません。
答えとして私のコメントを投稿することもできます:
%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ファイルから変数への値の読み取り から)