• 締切済み

C言語 CSVからTXTへ書き込み

CSVファイルのデータを配列に格納してtest.txtに書き込みたいです。 その際、指定した列だけを書き込むのですが、うまくいきません。 a.txtの中身が a1,a2,a3,a4,a5 b1,b2,b3,b4,b5 c1,c2,c3,c4,c5 だとしたら、a1,a2,a3,a4,a5だけしか書き込めていません。 test.txtに書き込みたいのは、 a3 b3 c3 のようにしたいです。 初心者ですが、なかなかうまくいかないのでくやしいです。。。 お詳しい方、ご教授よろしくお願いします。 #define LINE_MAX 1024 #define ITEM_MAX 200 FILE *fp; char in_file[] = "a.txt"; char line[LINE_MAX]; char delmit[] = ",\n";      char item[ITEM_MAX][100]; char *item_p; int item_idx,ii; if((fp = fopen(fnamebuff, "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[item_idx][0], item_p); } else { item[item_idx][0] = '\0'; } } } FILE *fl; fl=fopen("test.txt","w"); for(ii=0;ii<200;ii++){ fprintf(fl," %s ", &item[ii][0]); } fclose(fl); fclose(fp); } }

みんなの回答

回答No.7

>計算をさせているのですが、ちゃんと出力されません。 わかる範囲ではもちろん、対応しますけど。 ”ちゃんと”ではわからないので、どうしたい?のかを 書いてもらえますか? それと、 for(i=0;i<line_no;i++) { t[i] = atoi(item[i+3][1])-atoi(item[i+2][1]); v[i] = atoi(&item[i+3][2])-atoi(&item[i+2][2]); 現在のiは、最大値が、読み込めた行数なので、 最大行数に+3や、+2を足してはいけないのでは? item[ ここは何行目 ][ こっちが何カラム目 ] です。 a 1,2,3,4, b c d カラムは、X方向で、1234の位置で、行は、abcdのY方向です。 これをマトリックス的に見るならですが。 その辺を直してみてはいかがでしょうか? atoi でINT型にして、いるのになぜ、受け取りの方が、 double t[28600],v[28600]; DOUBLEなのかが、よくわかっていませんが、 値がDOUBLEなのであれば、表示もDOUBLEにするべきではないかと、 fprintf(fl,"%s %s %d\n",&item[i][1],&item[i][2],v[i]/t[i]); "%d"ではなく、"%f" にしておいたほうがいいかと。。 http://www9.plala.or.jp/sgwr-t/c/sec05.html printfの、後ろに書いているパラメーターは、キャストされないので、 注意が必要です。可変パラメーターを使っているため、何を書いてもいいという特性があるので、 INTだろうが、DOUBLEだろうが、エラーは出ません。。 v[i]/t[i] をINTで出すなら、最初からINTでキャストしておくべきかと。 (int)(v[i]/t[i])など。この場合、"%d"で表示。ただし、INTなので、小数点関連はありません。 "%f" で受け取れる場合は、そのままでもいいんですが、 個人的な書式では、その位置が、DOUBLEだということを、他の人が呼んでもわかるようにと (double)(v[i]/t[i]) とわざと、無意味なキャストを行っています。 実際には、double -> doubleなので、何もおきませんが、他の人が このソースを見たとき、ここが、DOUBLEなのだ!とすぐにわかるという意味合いでですが・・ ここは、好みで!

すると、全ての回答が全文表示されます。
回答No.6

あくまでこんなものは、サンプルなので、、 細かいチェックはしてませんから、そこはご注意を! たとえば、 item[line_no][item_idx][0] = '\0'; これですが、最初のstrtokがいきなりNULLだった場合は スルーしているので、初期化さえされないので、値は不定ですし。 文字の長さも決めうちなので、1バイトでもオーバーフローしたら メモリ破壊しまくりますので。 ちゃんとやるなら、長さを測ったり、可変長を扱えるライブラリなり関数を 用意して使うべきでしょうし。 暇つぶし回答なので、それほどは、本気になさらないでくださいね。 それでは!

yuta20041214
質問者

補足

こんばんわ!ご回答ありがとうございます! 今度は配列に格納したデータに少し計算を加えてTXTファイルに出力したいのですが、 charからdoubleにatoiを使って変換し、計算をさせているのですが、ちゃんと出力されません。 元データは文字と数字が含まれています。 "a1,b1,c1,d1" "1,2,3,4" "5,6,7,8" "9,10,11,12" "13,14,15,16" こんな感じです。実際はもっと大きなデータです。 お時間があればご回答よろしくお願いします。 #include <stdio.h> #include <string.h> #define LINE_MAX 3250 #define ITEM_MAX 200 FILE *fp,*fl; char line[LINE_MAX]; char delmit[] = ",\n"; char item[28600][ITEM_MAX][100]; char *item_p; int i; int item_idx; int line_no; double t[28600],v[28600]; int main(){ line_no=0; if((fp = fopen("a.txt", "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[line_no][0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[line_no][item_idx][0], item_p); }else{ item[line_no][item_idx][0] = '\0'; } } } line_no++; } } fl=fopen("test.txt","w"); for(i=0;i<line_no;i++) { t[i] = atoi(item[i+3][1])-atoi(item[i+2][1]); v[i] = atoi(&item[i+3][2])-atoi(&item[i+2][2]); fprintf(fl,"%s %s %d\n",&item[i][1],&item[i][2],v[i]/t[i]); } fclose(fl); fclose(fp); }

すると、全ての回答が全文表示されます。
回答No.5

a1,a2,a3,a4,a5,a3 b1,b2,b3,b4,b5,b3 c1,c2,c3,c4,c5,c3 最後に3番カラムを結合したい?ということであれば、 少し変更して、、 ------------- #include <stdio.h> #include <string.h> #define fnamebuff "a.csv" /* ファイル名変数なかったので、適当に作成 */ #define LINE_MAX 1024 #define ITEM_MAX 200 FILE *fp; char in_file[] = "a.txt"; char line[LINE_MAX]; char delmit[] = ",\n"; char item[200][ITEM_MAX][100]; /* 次元追加 */ char *item_p; int item_idx,ii; int line_no; /* 行番号追加 */ int culum_no; void text_filter(char *p) { int l=strlen(p); while(l>0) { l--; if (p[l]==10 || p[l]==13) { p[l]=0; }else{ return; } } return; } int main() { line_no=0; /* 行番号初期化 */ if((fp = fopen(fnamebuff, "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { text_filter(line); if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[line_no][0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[line_no][item_idx][0], item_p); }else{ item[line_no][item_idx][0] = '\0'; } } } line_no++; } } /* 画面表示タイプ */ for(ii=0;ii<line_no;ii++) { for(culum_no=0;culum_no<999;culum_no++) { if (item[ii][culum_no][0]) { if (culum_no) printf(","); printf("%s",item[ii][culum_no]); }else{ break; } } /* 最後に結合したいものを書いた */ if (culum_no) printf(","); printf("%s\n",item[ii][2]); } /* 文字列作成タイプ */ char line_buffer[256]; for(ii=0;ii<line_no;ii++) { line_buffer[0]=0; for(culum_no=0;culum_no<999;culum_no++) { if (item[ii][culum_no][0]) { if (culum_no) strcat(line_buffer,","); strcat(line_buffer,item[ii][culum_no]); }else{ break; } } /* 最後に結合したいものを書いた */ if (culum_no) strcat(line_buffer,","); strcat(line_buffer,item[ii][2]); /* 出力、fprintfでもなんでも好きに */ printf("out = \"%s\"\n",line_buffer); } } ------------- では、いかがでしょうか? ちなみ、先ほどのサンプル、ポインタが一部まちがってまして。 item[ii][2]これに&がついてました・・・失礼しました。 &つけるなら、&item[ii][2][0]ですね。ヘボミス連発です。 このサンプルの実行結果は、 $ cc a.c && ./a <-ここはこちらのコンパイラの名前ですので、無視してください。 a1,a2,a3,a4,a5,a3 b1,b2,b3,b4,b5,b3 c1,c2,c3,c4,c5,c3 out = "a1,a2,a3,a4,a5,a3" out = "b1,b2,b3,b4,b5,b3" out = "c1,c2,c3,c4,c5,c3" と出ますが、これでよろしかったでしょうか?

すると、全ての回答が全文表示されます。
回答No.4

>配列に格納したデータをCstringクラスの最後の列に代入したいのですが、 Cstring str; for(ii=0;ii<line_no;ii++) { str+=item[ii][2] } どういう、結果になれば正しいのでしょうか? "Cstring" < 私の方は、この書き方がわからないという感じはあります。 これだと、 "a3b3c3"こうなっちゃう?ということでいいのでしょうかね? 私の使うCで同じことをするのであれば、 char str[ 任意のバッファー ]; /* 余裕を見てサイズは作成 */ str[0]=0; < NULLを作成。 for(ii=0;ii<line_no;ii++) { /* a + ,b + ,c +,d = a,b,c,d */ /* カンマが着いていないのは、最初の一回のみなので、iiが0以外で","を結合 */ if (ii) strcat(str,","); /* もしもカンマ区切りにしたいならこの行を使う */ strcat(str,item[ii][2]); } と同じかな? この質問、結果がよくわからないので、どうしたい?のか 教えてもらえれば、回答できるとは思います。 こちら、GCCというコンパイラで、基本的な命令だけで、遊んでいるので。 マイクロソフト系?の書き方はよくわかっていませんで。そこはすいません。

yuta20041214
質問者

補足

私の質問の仕方が悪かったです。わかりにくくてすみません。。。 元のデータ a1,a2,a3,a4,a5 b1,b2,b3,b4,b5 c1,c2,c3,c4,c5 取り出したデータ a3 b3 c3 元のデータに取り出したデータを追加したいです。 a1,a2,a3,a4,a5,a3 b1,b2,b3,b4,b5,b3 c1,c2,c3,c4,c5,c3 上記のように。この元データがCstringクラスで宣言していたのですが、おっしゃる通りマイクロソフト系の宣言です。 AsarKingChangさん流の書き方を教えてくれませんか?

すると、全ての回答が全文表示されます。
回答No.3

ミスったままだと、恥ずかしいので、 #include <stdio.h> #include <string.h> #define fnamebuff "a.csv" /* ファイル名変数なかったので、適当に作成 */ #define LINE_MAX 1024 #define ITEM_MAX 200 FILE *fp; char in_file[] = "a.txt"; char line[LINE_MAX]; char delmit[] = ",\n"; char item[200][ITEM_MAX][100]; /* 次元追加 */ char *item_p; int item_idx,ii; int line_no; /* 行番号追加 */ int main() { line_no=0; /* 行番号初期化 */ if((fp = fopen(fnamebuff, "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[line_no][0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[line_no][item_idx][0], item_p); }else{ item[line_no][item_idx][0] = '\0'; } } } line_no++; } } for(ii=0;ii<line_no;ii++) { printf("%s ",&item[ii][2]); } } 作りました。 ファイルに出力せず、画面表示になっているので、 そこは、fprintfなりに入れ替えて置いてください。

yuta20041214
質問者

補足

ありがとうございます!できました!!AsarKingChangさん、お詳しいので追加で質問させていただきます。配列に格納したデータをCstringクラスの最後の列に代入したいのですが、 Cstring str; for(ii=0;ii<line_no;ii++) { str+=item[ii][2] } でよろしいでしょうか。他に良い方法はありますか。よろしくお願いします。

すると、全ての回答が全文表示されます。
回答No.2

あ、失礼。ミスってました。最初の無視してください。

すると、全ての回答が全文表示されます。
回答No.1

char delmit[] = ",\n";   デメリタは、","だけでは? なので、分解できていないと思いますよ。 一括で取り込む方式でやりたいのであれば、 item[][] これも、3次元配列のほうがいいのではないかと item[][][100] = 100は文字を格納するバッファーとして。 a1,a2,a3,a4,a5 b1,b2,b3,b4,b5 c1,c2,c3,c4,c5 item [0]= 0ライン目 item [0][0]= 0カラム目="a1"など item [0][0][0]="a1"などの文字列用の実体。 そうすれば、 item [ ライン番号 ][ カラム番号 ] で処理できるため、後々効率はいいかもしれません。 >test.txtに書き込みたいのは、 >a3 >b3 >c3 ならば、 item [0][2] が"a3".. item [1][2] が"b3".. item [2][2] が"c3".. あと、読み込めた行数を覚えておけば、最後に強制的に200行と指定している部分が 不要になるので、余計なバグを生まなくてすみます。 ただし、fgets の先頭が文字かは、軽くチェックした方がいいかもしれません。 改行コードや、EOFコードが入って来ることもありえる為。 #汎用性を求めるなら、やっておく方が親切でしょうね。 私の方では、こういう処理の時、 終端の改行コードを一番最初に削除しています。 最後のカラムは ”a5”に見えますが、実際には"a5"+改行コードがくっついてくるためです。 空行も、改行コードが入っていることがあり、この状態で、終端改行コード削除を行うと バッファーの先頭が0になるので、処理するか?の判定に使えて便利です。 C言語以外では、trimと呼ばれる処理ですが。trim_r()のほうが近いかな。 ということで、私なりの回答でした。

すると、全ての回答が全文表示されます。

関連するQ&A