ページ 1 / 1
CSVファイルの読み込み
Posted: 2011年7月06日(水) 18:11
by hibari
CSVファイルを読み込んで一つのクラスごと構造体のリストに入れたいのですが、うまくいきません。
下記が読み込みたいCSVファイルの一部です。
test.csv
コード:
3-1,鈴木,32
01,佐藤,男
02,田中,女
3-2,山川,35
01,石本,男
3-3,長谷川,33
01,安藤,女
02,一之瀬,女
03,緒方,男
構造体
コード:
typedef struct {
char stu_num[16]; /* 出席番号 */
char stu_name[16]; /* 生徒名 */
char stu_sei[16]; /* 性別 */
} Student;
typedef struct {
Student *student;
char cla_name[16]; /* クラス名 */
char cla_tea[16]; /* 担任名 */
char cla_num[16]; /* クラス人数 */
} Class;
単純に同じデータの並び、例えば
01,安藤,女
02,一之瀬,女
03,緒方,男
04,春子,女
05,夏子,女
06,秋子,女
07,冬子,女
.
.
.
みたいな感じなら読み込めますが、
上記のCSVファイルみたいになると方法が分かりません。
いい方法はないでしょうか?
Re: CSVファイルの読み込み
Posted: 2011年7月06日(水) 18:31
by バグ
1:Class構造体のデータを読み込みます。これはあなたが出来ると書いてある生徒を読み込むのと同じような手順です。(まぁ、構造体への展開部分だけがちょっと違いますが、ほぼ同じといって差し支えありません。)
2:Class構造体のメンバにcla_numというのがありますね?そこに生徒の人数が格納されていますので、atoi関数などで数値に変換してやります。これで、数値として生徒人数を取得することができます。
3:先ほど2で取得した生徒人数の回数だけ、あなたが出来ると書いてある生徒データの読み込みを実行するだけです。forループなどを使うといいと思います。
4:ファイルの終端でなければ、1に戻ります。
以上です。
Re: CSVファイルの読み込み
Posted: 2011年7月06日(水) 19:39
by non
1つのクラスに生徒は複数いるわけですが、
どのような構造で記憶しようと考えていますか?
Student *student;
このメンバーだということは、人数分のStudentを動的に確保し、その先頭アドレスを格納すると考えていいのでしょうか?
バグさんの2ですが、あらかじめ、cla_numに人数が格納されているわけではなくファイルを読み込むことで、
生徒人数分を取得し、その人数をcla_numに書き込むのではないのですか?
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 09:24
by hibari
構造体には何もデータが入っていない状態で、そこに読み込んだファイルのデータを格納するというものです。
>Student *student;
>このメンバーだということは、人数分のStudentを動的に確保し、その先頭アドレスを格納すると考えていいのでしょうか?
その考えです。
一つのクラス(3-1とか)ごとに改行してあるのですが、その改行部分をうまく認識できれば入れられると考えています。
が、どうしても出来ません。
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 09:24
by バグ
>>nonさん
non さんが書きました:バグさんの2ですが、あらかじめ、cla_numに人数が格納されているわけではなくファイルを読み込むことで、
生徒人数分を取得し、その人数をcla_numに書き込むのではないのですか?
test.csvが読み込みたいCSVファイルだと書かれているようなのですが・・・?
そこの先頭データがClass構造体のデータのように見えるので、test.csvの構造は、まずClass構造体のデータが書かれてあり、その後に人数分のStudent構造体のデータが書かれてあり、ファイルから読み込んだそれらのデータを別に用意したリストに格納していくのだろうと・・・解釈したのですが違うのかな?
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 09:29
by バグ
>>hibariさん
hibari さんが書きました:構造体には何もデータが入っていない状態で、そこに読み込んだファイルのデータを格納するというものです。
ここまではできるということでしたよね?
hibari さんが書きました:一つのクラス(3-1とか)ごとに改行してあるのですが、その改行部分をうまく認識できれば入れられると考えています。が、どうしても出来ません。
fgets関数でファイルから文字列を読み込んだあと、その文字列が「改行文字」のみだったら、次のクラスのデータを読み込む・・・みたいな処理でいかがでしょうか?
構造体単体のデータをファイルから読み込む処理だけでいいので、ご自身で書かれたプログラムコードをここに載せていただけませんか?
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 09:41
by non
バグ さんが書きました:
そこの先頭データがClass構造体のデータのように見えるので、test.csvの構造は、まずClass構造体のデータが書かれてあり、その後に人数分のStudent構造体のデータが書かれてあり、ファイルから読み込んだそれらのデータを別に用意したリストに格納していくのだろうと・・・解釈したのですが違うのかな?
おお,なるほど。これはうっかり。
>3-1,鈴木,32
この32は人数でしたか。
その下に,2人分しか生徒の名前がなかったから,年齢か何かだとばっかり思ってました。
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 09:44
by バグ
>>nonさん
まぁ、これも私の勝手な推測かもしれませんけどね(^_^;)
>>hibariさん
というわけで、CSVファイルフォーマットについての補足説明をお願いします
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 10:03
by hibari
コード:
Class x;
FILE *fp;
int i;
fscanf(fp, "%[^,],%[^,],%s", x.cla_name, x.cla_tea, x.cla_num); /* クラス名、担任名、クラス人数読み込み */
i = 0;
fscanf(fp, "%[^,],%[^,],%s", x.student[i].stu_num, x.student[i].stu_name, x.student[i].stu_sei); /* 出席番号、生徒名、性別読み込み */
i++;
fscanf(fp, "%[^,],%[^,],%s", x.student[i].stu_num, x.student[i].stu_name, x.student[i].stu_sei); /* 出席番号、生徒名、性別読み込み */
InsertR(list, n, x); /* ノードの挿入 */
ファイルは無事開けています。
強引にやって上記のコードで
3-1,鈴木,32
01,佐藤,男
02,田中,女
までは読み込めてます。
これをループさせたり、改行だけの行を読み込んだら次のリストに挿入する
等をやろうとすると動かなくなったり、無限ループに陥ったりしています。
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 10:34
by maru
ファイルから直接構造体に読み込むのではなく、いったん一行分の文字列バッファに読み込んで、それから分解すればいいんです。
そうすれば空行を読み飛ばすことは簡単です。
fgets, sscanf を使用すればよろしいかと。あとは for 文をうまく使えば。。。
構造体のメンバがすべて文字列ですけど、クラス人数は int にしたほうがよくないですか?
あと、性別も bool もしくは enum にしたほうが後の処理が楽になります。
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 16:48
by hibari
maru さんが書きました:ファイルから直接構造体に読み込むのではなく、いったん一行分の文字列バッファに読み込んで、それから分解すればいいんです。
そうすれば空行を読み飛ばすことは簡単です。
fgets, sscanf を使用すればよろしいかと。あとは for 文をうまく使えば。。。
構造体のメンバがすべて文字列ですけど、クラス人数は int にしたほうがよくないですか?
あと、性別も bool もしくは enum にしたほうが後の処理が楽になります。
何度試してもうまく動かないです。
fgetsやsscanfを使ってやってるのですが、空行を判定させることができません。
isspace等、色々試しても駄目です。
後から構造体メンバの型は変更しようと思っています。
とりあえずは今のままで、やりたいことができてから調整していきます。
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 18:21
by maru
うまくいかない原因の一つに、例にあるテキストのクラス人数と実際のクラスの名簿があっていない、ということがあるかと思います。
実際にプログラムを書いてみましたが、ちゃんと動くようになるまである程度時間がかかりました。
正しいデータでやってみることをお勧めいたします。
Re: CSVファイルの読み込み
Posted: 2011年7月07日(木) 18:32
by non
プログラム全部とテスト用のデータを添付してください。
Re: CSVファイルの読み込み
Posted: 2011年7月10日(日) 10:17
by 1964
hibari さんが書きました:CSVファイルを読み込んで一つのクラスごと構造体のリストに入れたいのですが、うまくいきません。
下記が読み込みたいCSVファイルの一部です。
上記のCSVファイルみたいになると方法が分かりません。
いい方法はないでしょうか?
コード:
#include <stdio.h>
#include <string.h>
#define CVSBUFFSIZE 1024
typedef struct {
char stu_num[16]; /* 出席番号 */
char stu_name[16]; /* 生徒名 */
char stu_sei[16]; /* 性別 */
} Student;
typedef struct {
int student_id[35];
char cla_name[16]; /* クラス名 */
char cla_tea[16]; /* 担任名 */
char cla_num[16]; /* クラス人数 */
} Class;
Class class[30];
Student student[200];
int main( void )
{
int curr_class=0;
int curr_student=0;
int student_wclass;
int class_defined = 0;
char buff[CVSBUFFSIZE];
char buff2[40];
FILE *rfp;
int nenn, kumi, ninzu;
char *ptannin;
int sekiban;
char *seitomei, *seibetu;
char *wptr;
rfp = fopen( "class.cvs", "r" );
do {
if( fgets( buff, CVSBUFFSIZE, rfp ) ) {
if( '\n' == buff[0] || '\n' == buff[1] ) continue;
if( 3 == sscanf( buff, "%d-%d,%s", &nenn, &kumi, buff2 ) ) {
wptr = strchr( buff2, ',' );
*wptr = '\0';
if( class_defined ) ++curr_class;
student_wclass=0;
sprintf( class[curr_class].cla_name, "%d-%d", nenn, kumi );
strcpy( class[curr_class].cla_tea, buff2 );
strcpy( class[curr_class].cla_num, wptr+1 );
class_defined = 1;
printf( "Debug Read class No: %d Name:%s\n", curr_class, class[curr_class].cla_name );
continue;
}
if( 2 == sscanf( buff, "%d,%s", &sekiban, buff2 ) ) {
wptr = strchr( buff2, ',' );
*wptr = '\0';
sprintf( student[curr_student].stu_num, "%d", sekiban );
strcpy( student[curr_student].stu_name, buff2 );
strcpy( student[curr_student].stu_sei, wptr+1 );
class[curr_class].student_id[student_wclass] = curr_student;
++ student_wclass;
++ curr_student;
printf( "Debug Read student No: %d Name:%s\n", curr_student, student[curr_student].stu_name );
continue;
}
}
} while( ! feof( rfp ) );
return 0;
}
下記をポインタにしてmalloc/reallocすればクラス数や合計生徒数などをメモリの許す限り無限に増やせます。
Class class[30];
Student student[200];
int student_id[35]; /*1クラス最大35名*/
} Class;