• ベストアンサー

配列の読み込み

タブ又はカンマ、又はスペースで区切られた配列が書かれたテキストを、配列として読み込みたいのですが、どのようプログラムしたらいいのでしょうか。 つまりは、下の例みたいに書かれたテキストを、そのまま3行4列の配列として読み込みたいのです。 例) 1222,2337,593,3488 2338,384,34,2229 534,23333,234,444 ちなみに、私は下のような1列で書かれたものなら読み込めます。 例) 123 343 23 253

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

  • ベストアンサー
  • L_E_D
  • ベストアンサー率48% (36/74)
回答No.1

こんにちは。 ご自身の勉強のために、あえてヒントだけを書きますと、 for fgets strtok を使用すればできます。ヘルプを見て下さい。 strtokの使い方がポイントです。 これで分からなければ、再度投稿します。

deeppurple14
質問者

補足

ありがとうございました。とりあえず、こうやってみました。でも無理でした。 int a[3][4]; char str[50]; FILE *fp; if((fp=fopen("test","r"))==NULL)exit(0); for(i=0;i<3;i++) { fgets(str,50,fp); for (j=0;j<4;j++) { a[i][j]=atoi(strtok(str,",")); } } 上の例で試したところ、配列aは以下のようになってしまいました。 1222,1222,1222,1222 2338,2338,2338,2338 534,534,534,534 strtokが、forループの中で毎回初めの数字を読み込んでいます。

その他の回答 (5)

  • hero1000
  • ベストアンサー率29% (114/390)
回答No.6

既に解決なさってるようですが一応・・・ No.2の補足に対する回答です。 >こんなかんじでいいでしょうか?  いいと思いますよ。 >列が非常に長いときは、strtokを使うしかないのでしょうか?  あまり長いと、sscanfで指定するフォーマットが長くなってしまうので、 よくないですね。("%d,%d,%d,%d,・・・"という感じになってしまうので)  strtokの方がスマートに書けると思います。 (No.3の補足に書いてあるとおりです)

  • L_E_D
  • ベストアンサー率48% (36/74)
回答No.5

方法としては、No.4の回答でほとんど問題はないと思います。 実際にコードを書く場合には、ループの回数=配列の大きさを #define で定義して 使用すると、間違いが少なくなるでしょう。 また、fscanfではなく、fgetsとstrtokの組合せを勧めたのもミスを防ぎ、配列の 大きさに柔軟に対応させるためです。 たとえば、読み込むファイルをExcelで作成し、CSV形式で保存すれば、上の例に あるファイルを作成できますが、行末にもカンマが付くことがあります。 例) 1222,2337,593,3488, fscanfを使用すると、書き方によっては最後のカンマのために、2行目以降の データが全てずれる可能性がありますが、No4の回答の例では、カンマがあっても 無くても正確に読み込めます。 どのようなフォーマットにしろ、テキスト(ascii)形式のファイルは、1行ずつ fgetsで読み込んでから処理する事をお勧めします。

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.4

# No.3お礼より こんな感じでどうでしょうか? for (i = 0; i < 3; i++) {   a[i][0] = atoi( strtok( fgets(str,50,fp),"," ) );   for (j = 1; j < 4; j++)     a[i][j] = atoi( strtok( NULL,"," ) ); } # 括弧の対応に要注意! # データを間違えて読むことより、不正な配列アクセスをする方が危険なので、確実に3行4列を超えないようにループを組む必要があります。   ↑非常に大事! またfscanfループの1つの解として、こんなのもあります。が、、、 for (i = 0; i < 3*4; i++)   fscanf(fp, "%d,", *a + i); これは必ずしも「よいプログラム」ではありません。 なぜなら「理解しにくい」からです(笑) # 理解しやすいコーディングというのはとても大切なことなのですが、プロでもできてない人が大勢いるんです。 # こういうことをやる人に限って、自分のコードは素晴らしいと思ってる人が多くって・・・ # 素直なプログラムを書けるように頑張りましょう。 leaz愚痴モードでした。

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

# No.1の補足に対して strtokは癖の強い関数なので、最初は悩みますよね。 この関数は内部に参照ポインタを持っていて、前回どこまで調べたかを覚えていてくれるのです。 2回目以降調べる場合は、第1引数にNULLを指定します。 最後まで調べ尽くすとNULLを返します。まぁ今回は数が分かっているので使いませんが。 以上を参考に改良をしてみてください。 # ただ、このような単純なフォーマットのテキストファイルならば、普通はfscanfのループで十分だと思いますが。

deeppurple14
質問者

お礼

ありがとうございます。 なるほど、下のように書けばうまくいきました。 for(i=0;i<3;i++) { fgets(str,50,fp); j=0; a[i][j]=atoi(strtok(str,",")); while(1) { j++; if((a[i][j]=atoi(strtok(NULL,",")))==NULL)break; } } この書き方でうまくいきますが、もっと効率のいい書き方ないでしょうか。 また、fscanfのループでうまくいくってのが分かりません。毎回先頭の数字を読み込みそうな気がしますが。

deeppurple14
質問者

補足

fscanfの方法も分かりました。どうもありがとうございます。 単純なフォーマットならfscanfかsscanfが便利で、複雑なフォーマットや列が長い場合は、strtokを使えばいいことが分かりました。

  • hero1000
  • ベストアンサー率29% (114/390)
回答No.2

1列のデータは4つの数字がカンマで区切られたものですので、  sscanf を用いればできると思います。 1列のデータを読み込んで、sscanfで数字を取り出して・・・。 と、ここまでにしておきます。 頑張って下さいね。

deeppurple14
質問者

お礼

ありがとうございます。下のように書いたところ、うまくいきました。 こんなかんじでいいでしょうか。 列が非常に長いときは、strtokを使うしかないのでしょうか? for(i=0;i<3;i++) { fgets(str,50,fp); sscanf(str,"%d,%d,%d,%d",&a[i][0],&a[i][1],&a[i][2],&a[i][3]); }

関連するQ&A

  • 連想配列の操作方法について

    A,B,C,D,E 1,3,4,5,7 2,4,6,7,10 4,5,1,4,8 このようなコンマ区切りテキストファイルを読み込み、次のような配列をつくるには、どうのようにしたよいか悩んでいます。 ご教授ください。 [A,1,2,4],・・・,[E,7,10,8] (行と列を置き換えるように配列を作成したい)

    • ベストアンサー
    • Perl
  • 【C++】行列データの読み込み

    C++でテキストファイルに以下のようにカンマ区切り(例なのでスペース等でも構いません)で記述された行列を2次元配列に格納する方法が分かりません。 例 1,2,3 4,5,6 7,8,9 よい方法があればご教授願います。

  • Rubyで配列をソートする

    15(tab)5634(改行) 24(tab)4446(改行) 24(tab)8357(改行) 24(tab)3287(改行) 56(tab)5465(改行) 56(tab)1324(改行) 56(tab)7544(改行) 上記のように1行にtabで区切られた2つの数値が並んでいるテキストファイルがあります。 このファイルを、Rubyを使って1列目が同じ数字の行ごとにソートしたいのですが、できなくて困っています。 上の例でしたら、1列目が24の3行を2列目の数値をキーとしてソート、1列目が56の3行を2列目の数値をキーとしてソートするということです。 一行ずつ読み込んで、array = line.split(/\t/)でタブでくぎって配列に格納するスクリプトを書いていたのですが、どうしてもできないので、力を貸していただけないでしょうか。 よろしくお願いします。

  • ファイルから読み込んで配列へ

    PerlでCGIスクリプト(掲示板もどき)を作成しています。 配列の操作がうまくいかず、ご教授頂きたいと思います。 <やりたい事> 1.ブラウザ上のフォームからの入力を、カンマ区切りでテキストファイルに追記して保存。 2.そのテキストの一部を使ってHTMLで表を作る。 <実際の作業> 1.フォームからのデータはcgi-lib.plで連想配列として受け取り、unshiftでテキストファイルへ追記する。 &ReadParse; #フォームからデータを受け取る $o=$in{'name'}; $p=$in{'mail'}; $q=$in{'title'}; $r=$in{'comment'}; open(IN,"xxx.txt"); @tmp1=<IN>; close(IN); #1件1行として新規データを追加する unshift (@tmp1,"$oo" , "," , "$pp" , "," , "$qq" , "," , "$rr","\n"); open(OUT,">xxx.txt"); print OUT @tmp1; close(OUT); 2.xxx.txtのデータを読み込んで、1列目(name)と3列目(title)だけを使った表を作る。 データを読み込む時点でつまづき、先に進めません。 <テキストファイルの例> 1行目:a,b,c,d 2行目:e,f,g,h 3行目:i,j,k,l 以下同様 <症状> print @tmp1;とすると、a~lの全てのデータが表示される。 $tmp1[0];とすると、(a)のみ表示される。 $tmp1[1];とすると、カンマ(,)が表示される。 $tmp1[2];とすると、(b)が表示される。 <質問> 一つの行(配列)に対して2回繰り返す処理(nameとtitle)と、行単位で繰り返す処理(1行目、2行目…)を合わせればいいのだろうと思っていますが、どうすればいいのかわかりません。 気分的には↓こんな感じです。 foreach { "行の処理" foreach { "列の処理" } } そもそも、区切り文字であるカンマが、配列に格納されている時点で失敗しているのかな?とも思っています。 宜しくお願いします。 なお、不足している情報がありましたら補足いたします。

    • ベストアンサー
    • Perl
  • テキストデータの読み込みについて

    C言語のテキストデータの読み込みについてです。 C言語のプログラムについてです。 2444,1114,2807, 1984,2845,2086, 658.1,-1564.0,1239.7, -102.0,958.4,123.1, 12.7,6.0,82.7 2439,1110,2802, 1973,2865,2108, 658.8,-1563.7,1239.6, -102.0,957.1,121.9, 12.8,6.0,82.7 2441,1106,2806, 1967,2888,2124, 659.4,-1563.5,1239.5, -102.2,956.4,121.0, 12.8,6.1,82.8 2440,1109,2808, 1964,2896,2127, 660.0,-1563.3,1239.4, -102.7,956.2,120.7, 12.8,6.1,82.8 2441,1112,2807, 1981,2894,2120, 660.6,-1563.0,1239.4, -103.3,956.2,120.1, 12.8,6.1,82.8                                       ↑ 上の様なカンマとスペースで15個に区切られているtxtファイルがあるのですが、このtxtデータの10コ目と11コ目をを計算で使いたく、取り出したいと考えているのですがscanfを使いどのように取り出すことが出来るのか、また取り出したデータから数値を引くことを教えて頂きたいです。 つまり -102.0   958.4 -102.0   957.1 -102.2 と 956.4 -102.7   956.2 -103.3   956.2,             を取り出して計算に使いたいです。 そして1番上の数値だと、 -102.0と958.4 を読み込み、例えばそれぞれ100を引いた値を配列に入れたいです。 -102.0と958.4 → -202.0 と 858.4 のように取り出したいです。 教えて頂きたいです。お願いします。

  • Visual C++を 用いたテキストファイル読み込み(応用)

    Microsoft Visual C++ 2008 Express Editionを使っています。 テキストファイルは 約5000行×6列の数値(のみ)になっております。(列間にスペースあり) いくつかある5000×6行テキストファイルの中から、ファイル名を入力することで任意のテキストファイルにアクセスし、さらに6列のデータをそれぞれ別の配列に格納するコンソールプログラムを考えていますが行き詰まっています。例えば、1列目を配列1、2列目を配列2、・・・といった具合です。 詳しい方、どうかよろしくお願いいたします。

  • 配列の座標指定について。

    たとえば、下のような10行10列の配列でdの3を指定したいときにどういう手段で行えばいいのでしょうか? 入力についてですがdと3の間にはスペースは空けません。 困っています。お願いいたします。 行がそろっていません。みにくいですがお許しください。 \\\a b c d e f g h i j  \\\\\\\\\\\\\\\\\\\\\\\\\\\ 0 \ 0 0 0 0 0 0 0 0 0 0 1 \ 0 0 0 0 0 0 0 0 0 0 2 \ 0 0 0 0 0 0 0 0 0 0 3 \ 0 0 0 0 0 0 0 0 0 0 4 \ 0 0 0 0 0 0 0 0 0 0 5 \ 0 0 0 0 0 0 0 0 0 0 6 \ 0 0 0 0 0 0 0 0 0 0 7 \ 0 0 0 0 0 0 0 0 0 0 8 \ 0 0 0 0 0 0 0 0 0 0 9 \ 0 0 0 0 0 0 0 0 0 0

  • 配列の並び替え

    下のように5つの配列がA~E列まであって、2、3行目にデータが入っています。このときに、2行目の値が3行目の値より小さい配列で、かつ、2行目の値が小さい順に並べる。その後に、3行目より、2行目の値の方が大きい配列を3行目の値が大きい順に並べるマクロコードを教えてください。   A B C D E←列      1  1 2 3 4 5←配列番号 2  4 9 8 6 2 3  1 5 7 10 3      ↑ 行    ↓     A B C D E 1  5 4 3 2 1 2  2 6 8 9 4 3  3 10 7 5 1

  • C言語を使って、ファイルの読み込みをして切り出して2次元配列に格納した

    C言語を使って、ファイルの読み込みをして切り出して2次元配列に格納したいのです。 1,2行目に配列の行の数と列の数が書かれ、3行目から改行とカンマ、スペースで区切られて配列が書かれているテキストを読み込んで2次元配列に格納する。 テキストの例) 4 3 1.1 1.2 1.3 1.4 1.5 2.1 2.2 2.3 2.4 2.5 3.1 3.2 3.3 4.4 3.5 というプログラムを書いています。色々と参考書やサイトを参考してとりあえずの形にはなったと思ったのですが、実行してもエラーが出ます。 どこまで動いているか調べたところ、一行ごとに読み出してそれを切り出して行くところでおかしな事をしてしまっているようですが、どう変えたらいいものか分かりません。 なので、その点のアドバイスと 大きさの分からないファイルから1,2行目を読み出すのはこれで変な動きをする恐れはないか の2点についてヒントでも構わないので、教えてください。 以下、書いたソースです(申し訳ないのですが、文字数の関係で一部省略しています。) #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[] ) { double ** mainhairetu; int size_x, size_y; /* size_x 行 size_y 列 */ int i,j,count=0,count2; int *cut,*temp2; double temp; char s2[] = " ,"; char gyou[10],*num; FILE *fil; while((fgets(gyou,10,fil)) !=NULL){ if(count == 0){ size_x=atoi(gyou); count++; }else if(count ==1){ size_y=atoi(gyou); count=count+1; }else{ break; } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ここでmallocを使ってcutとmainhairetuの2つの配列を作っています。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ count=0; for (i = 0; i < size_y+2; i++) { mainhairetu[i][0] = atof( strtok( fgets(cut,50,fil),s2 ) ); for (j = 1; j < size_x; j++){ if(count <=1){ count++; break; }else{ mainhairetu[i][j] = atof( strtok( NULL,s2 ) ); } } } for(i=0;i<size_y;i++){ for(j=0;j<size_y;j++){ printf("%f",mainhairetu[i][j]); } printf("\n"); } return(0); }

  • 外部ファイル読み込みと繰り返し処理について

    質問いたします。 javascriptのみでCSVなどの外部テキストから、 下記のように配列内に読み込むことは可能なのでしょうか? objabc[0].objdef["この部分を外部テキストから読み込みたい"] = "OK!"; また、改行やカンマ、タブなどでの区切りの回数分 処理を繰り返す方法を教えていただければと思います。