C言語でCSVファイルの読み込み方法についての質問

このQ&Aのポイント
  • C言語でCSVファイルの読み込みをする際に、[ ] で囲った文字列と最初の2つのデータのみを抽出する方法を教えてください。
  • 以下のコードを使用してCSVファイルの読み込みを試みた結果、[ ] で囲った文字列の抽出がうまくいきません。sscanfの使い方が間違っているのでしょうか?正しい動作をするためにはどうすればよいでしょうか?
  • コードの一部を紹介します。csvファイルの一行のセパレータを検出するために、if文を使用しています。
回答を見る
  • ベストアンサー

c言語 sscanf の書式についての質問です

C言語でCSVファイルの読み込みをしようとしています。CSVの中身は以下の2通りあります。 ・[ ] で囲った文字列(1行に1つだけ) ・データの並び(1行に2つ以上) 具体的には、[ ] で囲った文字列と、最初の2つのデータのみが抽出対象です。そこで以下のコードを書いてみましたが、最後に示すように、[ ] で囲った文字列がうまく抽出できません。以下のコードのようなsscanfの使い方は間違っているのでしょうか?正しく動作するにはどうすればよいか、教えて下さい。 ---------- 以下、ソースコード #include <stdio.h> #include <string.h> int main(void) {  FILE *fp;  char *fname = "test.csv";  char s1[32], s2[16];  int ret;  char str[128];    /* csvファイルの一行 */  char structName[32];  /* セパレータ名 */  fp = fopen( fname, "r" );  if( fp == NULL ){   printf( "%sファイルが開けません\n", fname );   return -1;  }  while( fgets( str, 128, fp ) != NULL ){      /* セパレータ */   if( str[0] == '[' ){    printf( "str = %s\n", str );    ret = sscanf( str, "[%s]\n", structName );    printf( "structName = %s\n", structName );    continue;   }      ret = sscanf( str, "%[^,],%[^,]", s1, s2 );      printf( "s1 = %s\n", s1 );   printf( "s2 = %s\n", s2 );  }  fclose( fp );  return ret; } ---------- 以下、"test.csv"の中身 [ABC] test01,10,11,1.0,1.1 test02,20,21,2.0,2.1 test03,30,31,3.0,3.1 [DEF] test04,40,41,4.0,4.1 ---------- 以下、実行結果 str = [ABC] structName = ABC] s1 = test01 s2 = 10 s1 = test02 s2 = 20 s1 = test03 s2 = 30 str = [DEF] structName = DEF] s1 = test04 s2 = 40

  • aneja
  • お礼率93% (379/405)

質問者が選んだベストアンサー

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

[]のなかに入る文字種は限定できるのでしょうか? 英数字に限定なら sscanf( str, "[%[A-Z,a-z,0-9]]\n", structName ); といった具合にしてやればいいでしょう %sの場合 TABや空白、改行までを取得しようとするので ABC]まで読み込んでしまうのだと思います

aneja
質問者

お礼

ご回答ありがとうございます。 教えていただいた方法で、できました!

その他の回答 (2)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

「うまく」と言って誰もがわかるのか? ってこと. ちなみに %[^]] の方がいいかもね.

aneja
質問者

お礼

「うまく」の定義を書くべきでした。初歩的なミスでお手間をとらせて申し訳ありません。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

「[ ] で囲った文字列がうまく抽出できません。」とはどういうことでしょうか? 何をもって「うまく抽出できていない」と判断しているのかわかりません.

aneja
質問者

お礼

質問に記載した入力データに対する実行結果が「[」と「]」で囲った文字列にならなかったので、正しく抽出できていないと判断しました。ご指摘の意味がわかりませんので、ご指摘の補足をお願いします。

関連するQ&A

  • sscanfでフォーマットに合っているかを調べるには。

    今,Cの関数で0-9,A-Zの4文字以内の文字列かどうか を調べたいのですが, int main() { int i; char str[] = "ABCD" /* 調べたい文字列1 */ char str1[]= "ABC@" /* 調べたい文字列1 */ char str2[]= "ABCDE" /* 調べたい文字列1 */ char *p; p = str; /* ここをstr1,str2に変える */ if (strlen(p) != 4) printf("エラーです\n"); for (i = 0; i < 4; i++) { if (!isupper(p[i]) && !isdigit(p[i])) { printf("えらーです\n"); return EXIT_FAILURE; } } printf("すべてOKです\n"); return EXIT_SUCCESS; } というようにすれば,strとstr1とstr2がフォーマットに合うかわかるのですが,これをsscanfの正規表現を使用して実装したいのですが,可能でしょうか。 int main() { int ret; char str[] = "ABCD" /* 調べたい文字列1 */ char str1[]= "ABC@" /* 調べたい文字列1 */ char str2[]= "ABCDE" /* 調べたい文字列1 */ char *p; chat tmp[30]; p = str; ret = sscanf(p, "%4[0-9A-Z]", tmp); if (ret != 1) { printf("エラーです\n"); return EXIT_FAILURE; } printf("すべてOKです\n"); return EXIT_SUCCESS; } といしょうとするならば,str1のときは,@までのABCの文字列がとれて,retには1が帰ってきてしまいます。 なにか4文字以内ということを実装できる正規表現の使い方はあるのでしょうか? ちなみに sscanf(str, "%1[0-9A-Z]%1[0-9A-Z]%1[0-9A-Z]%1[0-9A-Z]", tmp1, tmp2, tmp3, tmp4) という以外でわかる方,よろしくおねがいします。

  • c言語の問題

    以下のプログラムをコンパイルし、実行したところ、次のような画面が表示された。下記の関数定義部分を補いなさい。 gcc test.c ./a.out abc def answer = defabc 以下ソースコード #include<stdio.h> void stradd(char A[], char B[]); int main(){ char str1[100], str2[100]; scanf("%s", str1); scanf("%s", str2); stradd(str1, str2); printf("answer = %s\n", str2); } void stradd(char A[], char B[]){ } よろしくお願いします。

  • sscanfって・・・。

    #include<stdio.h> main() { char str[] = "aiueokkakikukekossashisusesottstituteto"; char a[20], b[20], c[20], d[20]; sscanf(str,"%[^k],%[^s],%[^t],%[^\0]",a,b,c,d); printf("%s\n",a); printf("%s\n",b); printf("%s\n",c); printf("%s\n",d); } 上のプラグラムでaはaiueoとちゃんと出力されるのですがb,c,dがちゃんと出力されないのはなぜでしょうか?与えられた文字を代える以外によい方法があれば教えてください。

  • ファイルの入出力で困っています(C言語)

    はじめまして、nathan3と申します。 昔、さらっとC言語を学んでいたので、仕事場でも活用できればと思い、勉強しなおしています。 以下のプログラムですが、コンパイルはするものの、実行がなされません。 sprintfをつかってファイルを作り、fprintfで読み込み、countで繰り返し別名のファイルを読み込み・作成し…といったプログラムを書いているつもりです。 調べながら書いた稚拙なプログラムですが、ここがちがう!というところをお教えいただけると大変助かります。 #include <stdio.h> int main(void){ FILE *fp,*fo; char *fname1; char *fname2; char s[100],t[100]; int ret,count; for(count = 0 ; count < 3 ; count++) { sprintf(fname1, "sankasha%d.txt", count); fp = fopen(fname1, "r"); if (fp == NULL){ printf("%s can't open a file\n", fname1); return -1; } sprintf(fname2, "matome%d.txt", count); fo = fopen(fname2,"w"); if (fo == NULL){ printf("%s can't open a file\n", fname2); return -1; } printf("--fscanf---"); while( (ret = fscanf(fp,"%[^,],%s", s, t)) != EOF ){ fprintf(fo,"%s ", t); } } fclose(fo); fclose(fp); return 0; } 何度見直しても間違いが見つからず困窮しております。 どうぞ、みなさまのお力をお貸しください! よろしくお願いいたします。

  • C言語 strtok

    失礼します。現在こちらでアドバイスを頂きfgetcを使用して配列に格納をすることができたのですが、CSVをカンマ区切りで格納したいのですが上手くいかず困っています。strtokを使用方法をドキュメントを読んでもうまく区切ったものを配列に入れる方法がわかりません 何卒よろしくお願いします。 ソースコード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define MAXITEM 1400 int split(char *str, const char *delim, char *outlist[]) { char *tk; int cnt = 0; tk = strtok(str, delim); while (tk != NULL && cnt < MAXITEM) { outlist[cnt++] = tk; tk = strtok(NULL, delim); } return cnt; } int main(void) { FILE *fp; char *fname = "testfile.csv"; char *tp; char *array[1400]; char *test[11][1400]; char c; int i = 0; int n,y; char *tp[1400]; fp = fopen(fname, "r"); if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } while ((c = fgetc(fp)) != EOF) { array[i] = (char)c; i++; } tp = strtok(array, ","); puts(*tp); while (tp != NULL) { tp = strtok(NULL, ","); if (tp != NULL)puts(tp); } for (n = 0; n < 11; n++) { for (y = 0; y < 1400; y++) { test[n][y] = tp[y]; printf("%c", test[n][y]); } } fclose(fp); return 0; }

  • c言語についての質問です

    あるdatファイルに時間と振幅のデータが入っているんですが振幅のデータのみを2乗してから2乗したものに1/2乗し正のものだけから振幅の最大値を求め、振幅の最大値の2割に達した時間を出力したいのですが、どのようにすればよいか分かりません。 サンプルプログラムを載せますのでおねがいします。 ちなみにdatファイルには 時間 振幅 時間 振幅 … となっています。 #include <stdio.h> int main(void) { const char * fname = "C2.dat"; char line[BUFSIZ]; double amp, time,arrival, max=0,max20; FILE *fp = fopen(fname, "r"); while (fgets(line, BUFSIZ, fp)) { sscanf(line, "%lf%lf", &time, &amp); if (amp > max) { max = amp; } } fclose(fp); printf("max: %.7lf\n", max); fp =fopen(fname,"r"); while (fgets(line, BUFSIZ, fp)){ sscanf(line, "%lf%lf" , &time, &amp); if(amp > max*0.2){ arrival = time; break; } } fclose(fp); printf("arrival:%.16lf\n",arrival); return 0; }

  • c言語プログラムについて

    http://www.post.japanpost.jp/zipcode/dl/kokagi.html から全国一括(1,735,160Byte)をダウンロード このファイルを使って、 Linuxマシン上で、 例えば、北海道札幌市中央区旭ケ丘 と入力すれば、0640941 と返却されるプログラム(引数はコマンドラインで)をcで作成したいと思っているのですが、ファイルのダウンロードとファイルの読み込みまでは出来たのですが、その後の「北海道札幌市中央区旭ケ丘 と入力すれば、0640941」からが分かりません。どなたか続きを教えて頂けないでしょうか? 使用OS:fedora 一応、ソースを載せておきます #include <stdio.h> int main(void){ FILE *fp; char *fname="ken_all.csv"; char d[100]; char e[100]; char f[100]; char g[100]; char h[100]; char i[100]; int ret,a,b,c; fp = fopen("ken_all.csv", "r"); if (fp == NULL) { printf("ファイルをオープンできませんでした\n",fname); return -1; } while( (ret = fscanf( fp, "%[^, ],%d,%d,%s,%s,%s,%s,%s,%s", &a, &b, &c, d, e, f, g, h, i ) ) != EOF ){ printf( "%d %d %d %s %s %s %s %s %s", a, b, c, d, e, f, g , h , i); } fclose(fp); return 0; }

  • C言語でCSVデータを読み込んで加工して保存したい

    C言語でCSVデータを読み込んで加工して保存したい。 CSVデータの中身は 1 -0.001 2 -0.11 3 -0.22 4 -0.625 5 -0.55 という式を、 一行目+0行目=答え(1) 答え(1)+2行目=答え(2) 答え(2)+3行目=答え(3)という処理を行い、 1 答え(1) 2 答え(2) 3 答え(3) 4 答え(4) 5 答え(5) とCSVファイルに加工して保存するプログラムを作りたいのですが、どのようなプログラムを追加すれば良いのか分かりません。恐らくCSV内部データを配列データに保存して、配列データをfor分にて計算していけばよいのでしょうが、分かりません。 プログラム例を記載していただけないでしょうか。 以下CSVファイルを読み込んで表示するプログラムを示します。下記プログラムに加筆をお願いいたします。 #include <stdio.h> int main(void) { FILE *fp; char *fname = "C:\\Users\\XXX\\Desktop\\aaa.csv"; char s[100]; int ret, n1, n2; float f1, f2; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません¥n", fname ); return -1; } while( ( ret = fscanf( fp, "%[^,],%d,%d,%f,%f", s, &n1, &n2, &f1, &f2 ) ) != EOF ){ printf( "%s %d %d %f %f", s, n1, n2, f1, f2 ); } fclose( fp ); return 0; }

  • fgets, sscanf, バッファ、ストリーム について

    ファイルからデータを入力するのに、fscanf の代わりに fgets と sscanf を用いようと考えています。 そこで、sscanf に与えるバッファ文字列を、ファイルストリームのように扱う方法は無いものでしょうか。 例えば以下のデータファイルに対して、以下のプログラムをうまく動作させるには、どのようにすればよいでしょうか。 どうぞ、よろしくお願いします。 (データファイル test.dat) n_data 4 1 3 8 4 (プログラム) #include <stdio.h> main() { int i, n_data, *data; char buf[100]; FILE *fp; fp = fopen ( "test.dat", "r" ); fgets(buf, 100, fp); sscanf( buf, "n_data %d\n", &n_data ); data = (int *)malloc( n_data * sizeof(int) ); for( i=0; i<n_data; i++ ){ fgets(buf, 100, fp); sscanf( buf, "%d", &(data[i]) ); } sscanf( buf, "\n" ); close( fp ); printf( "n_data %d\n", n_data ); for( i=0; i<n_data; i++ ) printf( " %d", data[i] ); printf( "\n" ); } ちなみに、2行の fgets(buf, 100, fp); をコメントアウトして、 "sscanf( buf," を "fscanf( fp," に変更するとうまく動作します。

  • c言語についての質問です

    c言語についての質問です。あるdatファイルに振幅と時間のデータが保存されています。 このdatファイルを読み込み振幅の最大値を求めてから振幅の2割の値を求めます。 そこから再度読み込み振幅の2割を超える時間まで読み込み越えた際の時間を出力したいのですが上手くいきません。途中がけのプログラムをのせるのでお願いします。 datファイルには 時間 振幅 時間 振幅 … のようになっています。 #include <stdio.h> #include <math.h> int main(void) { const char * fname = "C1rbc1(50,0)sq,almi00001.dat"; char line[BUFSIZ]; double amp, time,arrival, max=0,max20; FILE *fp = fopen(fname, "r"); while (fgets(line, BUFSIZ, fp)) { sscanf(line, "%lf%lf", &time, &amp); if (amp > max) { max = amp; max20=max*0.2; } } fclose(fp); printf("max: %.7lf\n", max); printf("0,2*max:%.7lf\n",max20); int main(void) { FILE *fp =fopen(fname,"r"); while (fgets(line, BUFSIZ, fp)){ sscanf(line,"%lf%lf",&time,&amp); if(amp>max20){ arrival=time; break; } } fclose(fp); printf("arrival:%.7lf\n",arrival); return 0; } }

専門家に質問してみよう