CSVファイルの読み込み

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
hibari

CSVファイルの読み込み

#1

投稿記事 by hibari » 8年前

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ファイルみたいになると方法が分かりません。
いい方法はないでしょうか?

アバター
バグ
記事: 130
登録日時: 9年前
住所: 愛媛県
連絡を取る:

Re: CSVファイルの読み込み

#2

投稿記事 by バグ » 8年前

1:Class構造体のデータを読み込みます。これはあなたが出来ると書いてある生徒を読み込むのと同じような手順です。(まぁ、構造体への展開部分だけがちょっと違いますが、ほぼ同じといって差し支えありません。)

2:Class構造体のメンバにcla_numというのがありますね?そこに生徒の人数が格納されていますので、atoi関数などで数値に変換してやります。これで、数値として生徒人数を取得することができます。

3:先ほど2で取得した生徒人数の回数だけ、あなたが出来ると書いてある生徒データの読み込みを実行するだけです。forループなどを使うといいと思います。

4:ファイルの終端でなければ、1に戻ります。

以上です。

non
記事: 1097
登録日時: 9年前

Re: CSVファイルの読み込み

#3

投稿記事 by non » 8年前

1つのクラスに生徒は複数いるわけですが、
どのような構造で記憶しようと考えていますか?
Student *student;
このメンバーだということは、人数分のStudentを動的に確保し、その先頭アドレスを格納すると考えていいのでしょうか?

バグさんの2ですが、あらかじめ、cla_numに人数が格納されているわけではなくファイルを読み込むことで、
生徒人数分を取得し、その人数をcla_numに書き込むのではないのですか?
non

hibari

Re: CSVファイルの読み込み

#4

投稿記事 by hibari » 8年前

構造体には何もデータが入っていない状態で、そこに読み込んだファイルのデータを格納するというものです。

>Student *student;
>このメンバーだということは、人数分のStudentを動的に確保し、その先頭アドレスを格納すると考えていいのでしょうか?
その考えです。

一つのクラス(3-1とか)ごとに改行してあるのですが、その改行部分をうまく認識できれば入れられると考えています。
が、どうしても出来ません。

アバター
バグ
記事: 130
登録日時: 9年前
住所: 愛媛県
連絡を取る:

Re: CSVファイルの読み込み

#5

投稿記事 by バグ » 8年前

>>nonさん
non さんが書きました:バグさんの2ですが、あらかじめ、cla_numに人数が格納されているわけではなくファイルを読み込むことで、
生徒人数分を取得し、その人数をcla_numに書き込むのではないのですか?
test.csvが読み込みたいCSVファイルだと書かれているようなのですが・・・?
そこの先頭データがClass構造体のデータのように見えるので、test.csvの構造は、まずClass構造体のデータが書かれてあり、その後に人数分のStudent構造体のデータが書かれてあり、ファイルから読み込んだそれらのデータを別に用意したリストに格納していくのだろうと・・・解釈したのですが違うのかな?

アバター
バグ
記事: 130
登録日時: 9年前
住所: 愛媛県
連絡を取る:

Re: CSVファイルの読み込み

#6

投稿記事 by バグ » 8年前

>>hibariさん
hibari さんが書きました:構造体には何もデータが入っていない状態で、そこに読み込んだファイルのデータを格納するというものです。
ここまではできるということでしたよね?
hibari さんが書きました:一つのクラス(3-1とか)ごとに改行してあるのですが、その改行部分をうまく認識できれば入れられると考えています。が、どうしても出来ません。
fgets関数でファイルから文字列を読み込んだあと、その文字列が「改行文字」のみだったら、次のクラスのデータを読み込む・・・みたいな処理でいかがでしょうか?

構造体単体のデータをファイルから読み込む処理だけでいいので、ご自身で書かれたプログラムコードをここに載せていただけませんか?
最後に編集したユーザー バグ on 2011年7月07日(木) 09:47 [ 編集 1 回目 ]

non
記事: 1097
登録日時: 9年前

Re: CSVファイルの読み込み

#7

投稿記事 by non » 8年前

バグ さんが書きました: そこの先頭データがClass構造体のデータのように見えるので、test.csvの構造は、まずClass構造体のデータが書かれてあり、その後に人数分のStudent構造体のデータが書かれてあり、ファイルから読み込んだそれらのデータを別に用意したリストに格納していくのだろうと・・・解釈したのですが違うのかな?
おお,なるほど。これはうっかり。

>3-1,鈴木,32

この32は人数でしたか。
その下に,2人分しか生徒の名前がなかったから,年齢か何かだとばっかり思ってました。
non

アバター
バグ
記事: 130
登録日時: 9年前
住所: 愛媛県
連絡を取る:

Re: CSVファイルの読み込み

#8

投稿記事 by バグ » 8年前

>>nonさん
まぁ、これも私の勝手な推測かもしれませんけどね(^_^;)

>>hibariさん
というわけで、CSVファイルフォーマットについての補足説明をお願いします

hibari

Re: CSVファイルの読み込み

#9

投稿記事 by hibari » 8年前

コード:

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,田中,女
までは読み込めてます。
これをループさせたり、改行だけの行を読み込んだら次のリストに挿入する
等をやろうとすると動かなくなったり、無限ループに陥ったりしています。

maru
記事: 150
登録日時: 8年前

Re: CSVファイルの読み込み

#10

投稿記事 by maru » 8年前

ファイルから直接構造体に読み込むのではなく、いったん一行分の文字列バッファに読み込んで、それから分解すればいいんです。
そうすれば空行を読み飛ばすことは簡単です。
fgets, sscanf を使用すればよろしいかと。あとは for 文をうまく使えば。。。

構造体のメンバがすべて文字列ですけど、クラス人数は int にしたほうがよくないですか?
あと、性別も bool もしくは enum にしたほうが後の処理が楽になります。

hibari

Re: CSVファイルの読み込み

#11

投稿記事 by hibari » 8年前

maru さんが書きました:ファイルから直接構造体に読み込むのではなく、いったん一行分の文字列バッファに読み込んで、それから分解すればいいんです。
そうすれば空行を読み飛ばすことは簡単です。
fgets, sscanf を使用すればよろしいかと。あとは for 文をうまく使えば。。。

構造体のメンバがすべて文字列ですけど、クラス人数は int にしたほうがよくないですか?
あと、性別も bool もしくは enum にしたほうが後の処理が楽になります。
何度試してもうまく動かないです。
fgetsやsscanfを使ってやってるのですが、空行を判定させることができません。
isspace等、色々試しても駄目です。

後から構造体メンバの型は変更しようと思っています。
とりあえずは今のままで、やりたいことができてから調整していきます。

maru
記事: 150
登録日時: 8年前

Re: CSVファイルの読み込み

#12

投稿記事 by maru » 8年前

うまくいかない原因の一つに、例にあるテキストのクラス人数と実際のクラスの名簿があっていない、ということがあるかと思います。
実際にプログラムを書いてみましたが、ちゃんと動くようになるまである程度時間がかかりました。
正しいデータでやってみることをお勧めいたします。

non
記事: 1097
登録日時: 9年前

Re: CSVファイルの読み込み

#13

投稿記事 by non » 8年前

プログラム全部とテスト用のデータを添付してください。
non

1964
記事: 5
登録日時: 8年前

Re: CSVファイルの読み込み

#14

投稿記事 by 1964 » 8年前

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;

閉鎖

“C言語何でも質問掲示板” へ戻る