タブ又はカンマ、又はスペースで区切られた配列が書かれたテキストを、配列として読み込みたいのですが、どのようプログラムしたらいいのでしょうか。

つまりは、下の例みたいに書かれたテキストを、そのまま3行4列の配列として読み込みたいのです。
例)
1222,2337,593,3488
2338,384,34,2229
534,23333,234,444

ちなみに、私は下のような1列で書かれたものなら読み込めます。
例)
123
343
23
253

このQ&Aに関連する最新のQ&A

A 回答 (6件)

こんにちは。


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

この回答への補足

ありがとうございました。とりあえず、こうやってみました。でも無理でした。
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ループの中で毎回初めの数字を読み込んでいます。

補足日時:2001/05/31 20:21
    • good
    • 0

既に解決なさってるようですが一応・・・


No.2の補足に対する回答です。
>こんなかんじでいいでしょうか?

 いいと思いますよ。


>列が非常に長いときは、strtokを使うしかないのでしょうか?

 あまり長いと、sscanfで指定するフォーマットが長くなってしまうので、
よくないですね。("%d,%d,%d,%d,・・・"という感じになってしまうので)
 strtokの方がスマートに書けると思います。
(No.3の補足に書いてあるとおりです)
    • good
    • 0

方法としては、No.4の回答でほとんど問題はないと思います。


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

# 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愚痴モードでした。
    • good
    • 0

# No.1の補足に対して


strtokは癖の強い関数なので、最初は悩みますよね。
この関数は内部に参照ポインタを持っていて、前回どこまで調べたかを覚えていてくれるのです。
2回目以降調べる場合は、第1引数にNULLを指定します。
最後まで調べ尽くすとNULLを返します。まぁ今回は数が分かっているので使いませんが。

以上を参考に改良をしてみてください。

# ただ、このような単純なフォーマットのテキストファイルならば、普通はfscanfのループで十分だと思いますが。

この回答への補足

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

補足日時:2001/05/31 21:58
    • good
    • 0
この回答へのお礼

ありがとうございます。
なるほど、下のように書けばうまくいきました。

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のループでうまくいくってのが分かりません。毎回先頭の数字を読み込みそうな気がしますが。

お礼日時:2001/05/31 21:28

1列のデータは4つの数字がカンマで区切られたものですので、


 sscanf
を用いればできると思います。

1列のデータを読み込んで、sscanfで数字を取り出して・・・。

と、ここまでにしておきます。
頑張って下さいね。
    • good
    • 0
この回答へのお礼

ありがとうございます。下のように書いたところ、うまくいきました。
こんなかんじでいいでしょうか。
列が非常に長いときは、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]);
}

お礼日時:2001/05/31 21:48

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

QC++で、テキストファイルを一行ずつ読み込んで配列に入れたいのですが、

C++で、テキストファイルを一行ずつ読み込んで配列に入れたいのですが、うまくできません!

テキストには -3.0
       1.0
       2.0

・・・などのように一行に一つの数値が入って縦に並んでいます。
それをひとつずつ読み込み、新しい配列(たとえばa[])に順番にいれたいのです。

a[1]=-3.0,a[2]=1.0、・・・と
なるように。

どうか、この初心者にご指導お願いいたします。

Aベストアンサー

fgetsは文字列として読み込みます。これを数値に変換すれば、とりあえずあなたが望んでいることができます。変換はatofを使います。また、atofを使用するときは#include <stdlib.h>が必要です。
例えば
#include <stdlib.h>
  :
double d;
  :
d=atof("-3.0");
とすると、文字列の-3.0が数値の-3.0に変換されdに入ります。

fscanf関数で読み込んでもできますが、書式とデータがあっていないと上手くいかないので注意してください。

QC言語で複数列のデータを1列のみ読み込みたい

行m列の任意のデータの処理を行うプログラムで,
列ごとの統計を行うためにm列目のデータを取り出したいのですが,うまくいきません.
どのようなコードを書けばいいでしょうか?

自分で作ってみたのは以下のようなプログラムです(ファイルを開いて→m列目の読み込みの部分)
EOFを使っているためか,行数のiには全データ数が入ってしまいます.


void main (void)
{
FILE* fp;

int i, j;
i=0, j=0;

char FilePath[500];
char Folder[100];
char File[50];

printf("Folder Name:");
scanf("%s",&Folder);

printf("File Name:");
scanf("%s",&File);

sprintf(FilePath,"%s/%s",Folder,File);

if(( fp = fopen (FilePath,"r")) == NULL){
printf("cannot open '%s'\n", FilePath);
exit(1);
} //ここまではうまく動きます


while (fscanf(fp, "%lf", &A[i][0]) != EOF{
i++;
}
while (fscanf(fp, "%lf", &A[0][j]) != EOF){
j++;
}

printf("A[%d][%d]", i, j);
int n, m;              //n,mはこの後for文で使いたいので登場してもらいました
printf("input 'n':");
scanf("%d", &n);
printf("input 'm':");
scanf("%d", &m);

行m列の任意のデータの処理を行うプログラムで,
列ごとの統計を行うためにm列目のデータを取り出したいのですが,うまくいきません.
どのようなコードを書けばいいでしょうか?

自分で作ってみたのは以下のようなプログラムです(ファイルを開いて→m列目の読み込みの部分)
EOFを使っているためか,行数のiには全データ数が入ってしまいます.


void main (void)
{
FILE* fp;

int i, j;
i=0, j=0;

char FilePath[500];
char Folder[100];
char File[50];

printf("Folder Name:");
scanf("%s",&...続きを読む

Aベストアンサー

>どのようなコードを書けばいいでしょうか?

 http://okwave.jp/qa/q7114321.html #3

 読み込み時に配列に格納しないで、
 文字列として1行読み込んでから、(数値化し)配列に格納する例です。

 「m列目のデータ」の前には、m - 1 個の空白があるので、それをカウントし数値化します。
 (ただし、文字列には空白が連続しないこと)

 「実数」を「整数」に、「コンマ」を「空白」に置き換えればよいかと。

 http://www.bohyoh.com/CandCPP/C/Library/fgets.html
 http://www.bohyoh.com/CandCPP/C/Library/atoi.html

Qファイルから数字列を16進数の数字列として読み込むためには?

C言語初心者です。
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef…
0135792468acebdf0135792468acebdf0135792468acebdf0135792468acebdf…

のようなファイルがあったときに、このファイルを自分で用意した配列num[]に1次元配列形式、かつ16進数で読み込むコードが思いつかず困っています。ファイルは複数行かつ複数列存在し、各行と各列はそれぞれ長さはマチマチとします。
つまり、例えば
1234abcdf
2315a
cedf45
のようなファイルをnum[20]という配列に格納したいのです。

この場合、fgetc, fgets, fscanf等、使える関数は数種類あると思うのですが、どの方法がもっとも効率的に、かつ高速に自分が用意した配列numに読み込めるのでしょうか?

また、メモリ量もできるだけ節約したいので、同状況でmalloc等で読み込んだファイルの文字数のみの要素数を確保するやり方も考えているのですが、これも思いつかずに困っています(つまり、num[10000]とかをやるのは避けたいということです)

C言語に堪能な方がおられましたらご教授下さい。具体的なソースで説明していただけると助かります。

C言語初心者です。
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef…
0135792468acebdf0135792468acebdf0135792468acebdf0135792468acebdf…

のようなファイルがあったときに、このファイルを自分で用意した配列num[]に1次元配列形式、かつ16進数で読み込むコードが思いつかず困っています。ファイルは複数行かつ複数列存在し、各行と各列はそれぞれ長さはマチマチとします。
つまり、例えば
1234abcdf
2315a
cedf45
のようなファイルをnum[20]という配列に格納したいのです。

こ...続きを読む

Aベストアンサー

こんにちは。

#3の方が書かれているように、
C言語でファイルサイズを取得する方法はいくつかあると思います。

◎参考サイト
C言語 ファイル位置の取得 ファイルサイズの取得
http://simd.jugem.jp/?eid=57

fseek、および ftell によるファイルサイズを求める方法を用いて、今回の案件の処理を行う
サンプルプログラムを作ってみました。(下記参照)
ファイル読込みには、fgets を使用しています。
なお、今回のサンプルで扱えるファイルのファイルサイズ上限は、2GByteまでとなります。

注)間違っている点があるかもしれませんので、あくまで参考程度として下さい。

■サンプルプログラム

実行の際は、コマンドライン引数に、入力ファイル名(16進文字列が記述されたテキストファイル
のファイル名)を指定して実行して下さい。

注)以下のソースには、インデント(字下げ)のため、全角スペースが入っています。
  コンパイルの際は、半角スペースorタブへ置換するか削除して下さい。

---------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* define const */
#define MAXBUF 256

/* prototype */
int ConvHex2Bin( char cHex, unsigned char *cBin );
void DumpBinBuf( unsigned char *pBinBuf, long nBinLen );

/*
* main
*/
int main( int argc, char *argv[] )
{
  char *psFileName;
  FILE *fpInp;
  int ists;
  int ierr;
  int i, len;
  long nGetSize;
  long nPos, nBinLen;
  char cch;
  unsigned char bch;
  unsigned char *pBinBuf;
  char strLine[MAXBUF+1];

  //コマンドラインのチェック
  if(argc < 2){
    printf( "## Command Line Error!! (Not File Name)\n");
    return -1;
  }
  psFileName = argv[1];

  //入力ファイル名の表示
  printf( "Input File Name: \"%s\"\n", psFileName );

  //入力ファイルオープン
  if((fpInp = fopen( psFileName, "rb" )) == NULL){
    printf( "## File Open Error!!\n" );
    return 1;
  }

  //入力ファイルのサイズを取得
  //※ファイル末尾へシークしてファイルポジションを取得
  ists = fseek( fpInp, 0L, SEEK_END );
  if(ists){
    printf( "## File Seek Error (SEEK_END)!!\n" );
    fclose( fpInp );
    return 2;
  }
  nGetSize = ftell( fpInp );
  if( nGetSize == -1L ){
    printf( "## File Point Error ! (ftell)!\n" );
    fclose( fpInp );
    return 3;
  }

  //入力ファイルのサイズ表示
  printf( "Input File Size: %ld (byte)\n", nGetSize );

  //ファイルポジションを先頭に移動
  ists = fseek( fpInp, 0L, SEEK_SET );
  if(ists){
    printf( "## File Seek Error!! (SEEK_SET)\n" );
    fclose( fpInp );
    return 2;
  }

  //バイナリバッファのメモリ確保
  pBinBuf = (unsigned char *)malloc( nGetSize );
  if(pBinBuf == NULL){
    printf( "## Memory Allocate Error!!\n" ) ;
    fclose( fpInp );
    return 4;
  }

  //ファイル読込み&バイナリバッファへ格納
  nPos = 0;
  ierr = 0;
  while( fgets( strLine, MAXBUF, fpInp ) != NULL )  //1行読込み
  {
    //1行毎に読込んでバイナリバッファへ格納
    len = strlen( strLine );
    for( i=0; i<len; i++ )
    {
      cch = strLine[i];
      if(cch != '\r' && cch != '\n'){      //改行文字以外?
        ists = ConvHex2Bin( cch, &bch );  //HEX文字→バイナリ値変換
        if(ists == 0){
          pBinBuf[nPos++] = bch;      //バイナリバッファへセット
        }
        else {
          ierr = 1;
          break;    //エラーならループを抜ける
        }
      }
    }
    if(ierr) break;    //エラーならループを抜ける
  }
  nBinLen = nPos;    //読込んだデータ長を取得

  //ファイルクローズ
  fclose( fpInp );

  //16進文字以外が有った場合のエラー表示
  if(ierr){
    printf( "## File format Error!!\n" );
    if(pBinBuf != NULL){
      free( pBinBuf );
      pBinBuf = NULL;
    }
    return 5;
  }

  //バイナリデータのデータ長を表示
  printf( "Bin data Length: %ld (byte)\n", nBinLen );

  //バイナリデータのダンプ
  printf( "** Binary data Dump **\n" );
  DumpBinBuf( pBinBuf, nBinLen );

  //確保したメモリの解放
  if(pBinBuf != NULL){
    free( pBinBuf );
    pBinBuf = NULL;
  }

  return 0;
}

/*
* ConvHex2Bin : HEX文字→バイナリ値変換
*/
int ConvHex2Bin( char cHex, unsigned char *cBin )
{
  *cBin = 0;

  if(cHex >= '0' && cHex <= '9'){
    *cBin = cHex - '0';
  }
  else if(cHex >= 'a' && cHex <= 'f'){
    *cBin = cHex - 'a' + 10;
  }
  else if(cHex >= 'A' && cHex <= 'F'){
    *cBin = cHex - 'A' + 10;
  }
  else {
    *cBin = '.';
    return -1;
  }

  return 0;
}

/*
* DumpBinBuf : バイナリデータのダンプ
*/
void DumpBinBuf( unsigned char *pBinBuf, long nBinLen )
{
  long nPos;
  unsigned char bch;

  printf("Address : +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F\n");

  for(nPos=0; nPos<nBinLen; nPos++)
  {
    if((nPos % 16L) == 0){
      printf("%08lx:", nPos);
    }

    bch = pBinBuf[nPos];
    if(bch >= 0 && bch < 16){
      printf(" %1x", bch);
    }
    else {
      printf(" .");
    }

    if( (nPos+1) == nBinLen || ((nPos+1) % 16L) == 0 ){
      printf("\n");
    }
  }
}
---------------------------------------------------------

■プログラムの実行例
◎入力ファイル("test.txt")が下記内容だった場合
1234abcdf
2315a
cedf45

◎実行結果
Input File Name: "test.txt"
Input File Size: 26 (byte)
Bin data Length: 20 (byte)
** Binary data Dump **
Address : +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00000000: 1 2 3 4 a b c d f 2 3 1 5 a c e
00000010: d f 4 5

こんにちは。

#3の方が書かれているように、
C言語でファイルサイズを取得する方法はいくつかあると思います。

◎参考サイト
C言語 ファイル位置の取得 ファイルサイズの取得
http://simd.jugem.jp/?eid=57

fseek、および ftell によるファイルサイズを求める方法を用いて、今回の案件の処理を行う
サンプルプログラムを作ってみました。(下記参照)
ファイル読込みには、fgets を使用しています。
なお、今回のサンプルで扱えるファイルのファイルサイズ上限は、2GByteまでとなります。

注)...続きを読む

Qカンマ区切りのデータを配列に読み込みたい

趣味でゲームを製作しているのですが、その中で、
マップデータのテキストファイルを二次元配列に読み込むようにしています。
データファイルは、カンマ区切りで、例えば、
1,2,3,4,5
5,4,3,2,1
1,2,3,4,5
というようになっています。

fp=fopen(path,"r");
for(j=0; j<3; j++)
{
for(i=0; i<5; i++)
{
char c;
do{c=(getc(fp));}
while(c==','||c=='\n'||c=='\r');
map[j][i] = c-'0';
}
}

配列の各要素に読み込む中身が、0~9など1文字に限られている場合、このgetc()を使う方法で問題ないのですが、0~255など、文字数がまちまちになると、1文字を取り出すgetc()ではできなくなってしまいます。

これがどうすれば可能になるのか、情けないのですがちょっと思いつかないので、アドバイスを頂ければ幸いです。

Aベストアンサー

少し手を入れたらできそうですね。


{
char c;
do{c=(getc(fp));}
while(c==','||c=='\n'||c=='\r');
//-----------追加-----ここから
// int calc; の宣言要
calc = 0;
do { calc = (c - '0') + (calc*10);}
while(isdigit(c=getc(fp)));
//-----------追加-----ここまで
map[j][i] = calc;
}

QCで二次元配列の読み込み

はじめまして。
hiraです。
今非常に基本的であろうことに悩んでいます。まだまだプログラムを始めたところなのでうまくいきません。
内容は・・・

あるファイルを読み込んで、二次元の配列に格納していく。

です。

具体的には
test.txtというファイルがあり、中身は数字の二次元配列です。
カンマやtabで区切られています。配列の大きさ、数字の桁数などはファイルによって違います。
そのファイルを読み込んで、配列に格納したいと考えています。
今は一列を読み込むことには成功しています。そこからどのようにして分けて言ったらいいのか・・・ご教示お願いします。

もしくは、もっと違う方法で読み込む方法があればよろしくお願いします。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
FILE *fin;
char array[256];
char buf[256];

fin=fopen("test.txt","r");
if(fin == NULL){

printf("%sがオープンできません\n",fin);
exit(1);
}
while(fgets(buf,256,fin) != NULL)
{
          ここが問題・・・
}
fclose(fin);
return 0;
}

はじめまして。
hiraです。
今非常に基本的であろうことに悩んでいます。まだまだプログラムを始めたところなのでうまくいきません。
内容は・・・

あるファイルを読み込んで、二次元の配列に格納していく。

です。

具体的には
test.txtというファイルがあり、中身は数字の二次元配列です。
カンマやtabで区切られています。配列の大きさ、数字の桁数などはファイルによって違います。
そのファイルを読み込んで、配列に格納したいと考えています。
今は一列を読み込むことには成功しています。そ...続きを読む

Aベストアンサー

★『strchr』、『strpbrk』、『strtok』などの文字列関数を使う。
・どの関数を使ってもカンマ、タブ区切り、数字を切り分けてくれます。
・サンプルとして『strtok』関数バージョンを紹介します。
・『while』文の内部のみです。

サンプル:
char buff[ 256 ];
char *tokn = ",\t"; ←カンマとタブ文字を指定
char *seek; ←文字列のシーク移動用

while ( fgets(buff,sizeof(buff),fin) != NULL ){ ←sizeof(buff)で『buff』のサイズ(256)になる
 if ( (seek = strtok(buff,tokn)) != NULL ){
  do {
   /*
   value = atoi( seek ); ←『atoi』関数で数字文字列を整数に変換して value にセット
   ここは出題です。
   */
  } while ( (seek = strtok(NULL,tokn)) != NULL );
 }
}

最後に:
・最初の if の『strtok』関数で切り分ける文字列『buff』と区切り文字群『tokn』で最初の数字セルを
 取得します。取得後に do-while 部分で数字文字列を整数に変換して2次元配列へセットします。
 ここの部分は、質問者さんが実装して下さい。→『atoi』関数で整数変換できるので頑張って下さい。
・次に while の『strtok』関数で続きの切り分ける文字列を取得します。
 もしも、カンマやタブ文字が見つからないと NULL を返しますので do-while 文を抜けます。
・これで1行単位で『数字,数字,数字,…,数字』という CSV 形式のデータを2次元配列にセットできます。
・上記のはあくまでサンプルですので、2次元配列へのセット部分は hira1234 さんが記述して下さい。

参考URL:http://www9.plala.or.jp/sgwr-t/lib/strtok.html

★『strchr』、『strpbrk』、『strtok』などの文字列関数を使う。
・どの関数を使ってもカンマ、タブ区切り、数字を切り分けてくれます。
・サンプルとして『strtok』関数バージョンを紹介します。
・『while』文の内部のみです。

サンプル:
char buff[ 256 ];
char *tokn = ",\t"; ←カンマとタブ文字を指定
char *seek; ←文字列のシーク移動用

while ( fgets(buff,sizeof(buff),fin) != NULL ){ ←sizeof(buff)で『buff』のサイズ(256)になる
 if ( (seek = strtok(buff,tokn)) != NULL ){
  d...続きを読む


人気Q&Aランキング

おすすめ情報