- ベストアンサー
C言語 テキストファイルから比較
日付:2004/02/02 17時30分 体重:91.0 体脂肪率:21.0 除脂肪体重:71.9 日付:2004/02/04 20時47分 体重:88.6 体脂肪率:24.0 除脂肪体重:67.3 日付:2004/02/05 18時43分 体重:88.2 体脂肪率:22.5 除脂肪体重:68.4 日付:2004/02/06 18時35分 体重:88.4 体脂肪率:21.5 除脂肪体重:69.4 テキストファイルに以上のように入力されている場合に 除脂肪体重が多いもの3つだけを抜き出す(除脂肪体重だけを変数に入力する)には どの用にすればよいのでしょうか? アドバイスでも構いません。教えてください。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
テストしてないので間違ってるかもしれませんが こんなのはどうでしょう? //lineにはfgetsなどで解析する文字列を代入してください char *line = "日付:2004/02/02 17時30分 体重:91.0 体脂肪率:21.0 除脂肪体重:71.9"; int n,i; char str[5]; n = strlen(line); //文字列を最後から見て行って':'を探します while(line[n] != ':'){ n--; } n++; i = 0; //文字列を数値に変換するatoi()は「.」があると正しく処理されないので取り除く必要があります while(line[n] != '\0'){ if(line[n] == '.'){ n++; } str[i] = line[n]; n++; i++; } これで71.9の10倍である719の文字列がstrに入るのでそれをatoi()で数値に変換すればいいと思います。 ただしこれだと小数点第1位のみしか対応していません。 小数点がない場合や第2位まである場合にはさらに追加の処理が必要です。
その他の回答 (7)
- HOGERA3
- ベストアンサー率35% (50/139)
#7です。 ちょっと訂正です。 「日付」のところだけコロンが全角なんですね。 ですから、質問の1行目は以下のように分割されます(strtok()の戻り値は以下のようになります)。 ---------- 日付:2004/02/02 17時30分 体重 ←strtok()1回目 91.0 体脂肪率 ←2回目 21.0 除脂肪体重 ←3回目 71.9 ←4回目 ---------- >#define N 4 /* 除体脂肪体重は4番目だから */ 「日付」の後のコロンも半角だったら #define N 5 になります。
補足
なんかそこだけ全角にしてしまったすみません。 ありがとうございます。
- HOGERA3
- ベストアンサー率35% (50/139)
#3,5です。 自分で紹介しておきながら申し訳ないんですけど、 ご質問の場合だと strtok()には向いていないかも しれませんね。 コロンで分けるとこんなふうに↓ 分かれてしまいますから。 ---------- 日付 2004/02/02 17時30分 体重 91.0 体脂肪率 21.0 除脂肪体重 71.9 ---------- > やってみたんですが漢字が入っていると難しいようです。 私の環境(winXP cygwin gcc3.3.1)で 以下のようにやってみたらうまくいきました。 とりあえず参考まで。 #define BUFFSIZE 256 #define N 4 /* 除体脂肪体重は4番目だから */ char buff[BUFF_SIZE]; FILE *fp = fopen(filename, "r"); /* 1行読み込んで */ while (fgets(buff, BUFF_SIZE, fp) != NULL) { char *temp; double weight; int i; /* コロンでトークン分割して */ strtok(buff, ":"); for (i = 0; i < N - 1; ++i) temp = strtok(NULL, ":"); /* 数値に変換 */ weight = strtod(temp, NULL); printf("weight (except fat): %.2f\n", weight); } fclose(fp);
お礼
再度回答ありがとうございます。 漢字ではなくコロンで移動していくようにしているのですね。 これでもうまくいきました。 いろいろな角度からアプローチできて とてもいい経験になりました。 ありがとうございます。
- jagd-doga
- ベストアンサー率31% (14/45)
fgets()でファイルを1行ずつ読み出して、 strstr()でポインタを「除脂肪体重」まで移動させて、 sscanf()で数値を読み出せばOKだと思います。 ●strstr()を使えば「strlen()を使って4文字分戻る」よりもシンプルなソースを書けます。 参考までにこんな感じです。 char buf[0x80]; /* 読み出し領域 */ char *ptr; /* ワークポインタ */ float weight; /* 除脂肪体重値 */ /* ファイルを1行ずつファイルの最後まで読み出す */ while( fgets(buf,sizeof(buf),fp) != NULL) { /* fgets()で読み出した文字列から"除脂肪体重"を検索 */ ptr = strstr(buf, "除脂肪体重"); /* "除脂肪体重"を検出した場合 */ if( ptr != NULL ) { /* 数値を読み出す */ sscanf(ptr, "除脂肪体重:%e", &weight); } } ●すみません。sscanfって小数を読み出せるのか、小数を使う習慣が無いので自信ありません。 自分なら整数部分と小数点以下を別々の変数(int型)で扱うかも・・・
お礼
アドバイスありがとうございます。 この質問をしてみておそらく基本的なものであろう 関数をほとんど知らないのだと気づかされました。 試してみたところうまく行きました。 ありがとうございます。
- HOGERA3
- ベストアンサー率35% (50/139)
文字列を実数に直す関数に strtof() と strtod() があったと思います。 使い方はこんなかんじ↓。 #include <stdlib.h> char *str = "69.4"; float f = strtof(str, NULL); /* floatにする場合 */ double d = strtod(str, NULL); /* doubleにする場合 */
お礼
アドバイスありがとうございます。 新たな知識を得ることができてうれしいです。
- HOGERA3
- ベストアンサー率35% (50/139)
各項目がコロンで区切られてるようですから、 strtokを使うという方法もありますね。 ファイルからfgetsで読み込んで それをstrtokで分解。そして数値に変換。
お礼
回答ありがとうございます。 strtokという関数をはじめて知りました。 これなら楽に作れそうです。
補足
やってみたんですが漢字が入っていると難しいようです。
- asuca
- ベストアンサー率47% (11786/24626)
strlenでも文字列の長さをはかってそこからマイナス4文字分をポインタを使ってほかの変数に代入して数値変換すればいいかと思うんですが。
お礼
回答ありがとうございます。 これで解決できそうです。
- mi-si
- ベストアンサー率35% (200/567)
1行ごとに文字列を解析して、構造体に放り込みます。 除脂肪体重だけ必要な場合は変数1個で良いです。 上から3つ取り出す場合、 1.ソートしてから上から3つを抜き出す。 2.最初から多い3つだけを残す。 2の場合は、 weightdata,nowは除脂肪体重を格納する配列と変数 File *fp; double now,weightdata[3]; weightdata[0] = 0.0; //1st weightdata[1] = 0.0; //2nd weightdata[2] = 0.0; //3rd ... do { now = parsedata(fp); /* EOFの場合はマイナスを返す */ if (now > weightdata[0]) { weightdata[2] = weightdata[1]; weightdata[1] = weightdata[0]; weightdata[0] = now; } else if (now > weightdata[1]) { weightdata[2] = weightdata[1]; weightdata[1] = now; } else if now > weightdata[2]) { weightdata[2] = now; } } while (now >= 0.0);
お礼
アドバイスありがとうございます。 質問の仕方だが悪かったのですが 数値を取り出せれば上位3つを選び出すことは 自分でもわかるのですが文字列の解析の仕方がわかりません。 できればもう一度アドバイスよろしくお願いします。
お礼
回答ありがとうございます。 実際にプログラムまで作ってもらって非常にありがたいです。 ひとつ気になったのはatoiではなくatofを使えばもっと簡単に処理できるのではないですか? 早速作ってみようと思います。
補足
作ってみました。(めちゃくちゃ複雑…) void rank(void){ FILE *fp; int n,i,j,k[3]; double a,b[3]; char p[100][80],str[80]; for(i=0;i<3;b[i]=0,k[i++]=0); i=j=0; if((fp=fopen("tj.txt","r"))==NULL){ printf("ファイルを読み込めません。\n"); exit(1); } do{ fgets(p[j],79,fp); if(!feof(fp)){ n=strlen(p[j]); while(p[j][n-1]!=':')n--; while(p[j][n]!='k')str[i++]=p[j][n++]; } str[i]='\0'; i=0; a=atof(str); if(b[0]<a){ b[2]=b[1];b[1]=b[0];b[0]=a; k[2]=k[1];k[1]=k[0];k[0]=j; } else if(b[1]<a){ b[2]=b[1];b[1]=a; k[2]=k[1];k[1]=j; } else if(b[2]<a){ b[2]=a; k[2]=j; } j++; }while(!feof(fp)); printf("第1位 %s",p[k[0]]); printf("第2位 %s",p[k[1]]); printf("第3位 %s",p[k[2]]); fclose(fp); }