ページ 11

csvファイルからの取得

Posted: 2011年11月05日(土) 03:32
by kana
アルゴリズムの授業で出された課題で,
8:34,>>,>>,>>,>>,>>,9:06,>>,>>,>>,>>,>>,>>,9:28,>>,>>,>>,9:39
9:33,>>,>>,>>,>>,>>,10:00,>>,>>,>>,>>,>>,>>,10:23,>>,>>,>>,10:35
8:39,8:44,8:49,9:02,9:07,9:12,9:17,9:21,9:28,9:32,9:36,9:41,9:45,9:51,9:56,10:01,10:04,10:09
,,,,,,8:54,8:59,9:05,9:09,9:12,9:24,9:28,9:35,9:40,9:45,9:48,9:53
この要領でcsvファイルに18*48行に渡って記されている時刻を
構造体
typedef struct CELL{
int hour;
int min;};
に定義され,main関数で宣言された
struct CELL jikoku[18][48];
に、時間、分と的確に格納する関数を定義しようとしてます.

自分でしらべてfgetsでファイルfpから1行ずつ取得のお約束に
sscanfでやってみましたが空白や>>のパターンの多さに苦戦してできませんでした.

分解して格納使用かと考えたのですが調べても見つからず,学校ではrndくらいしかやってないので全くわかりません。
どなたか分解の仕方,またどう分解されるかなど教えていただけないでしょうか。

Re: csvファイルからの取得

Posted: 2011年11月05日(土) 06:16
by bitter_fox
kana さんが書きました:アルゴリズムの授業で出された課題で,
8:34,>>,>>,>>,>>,>>,9:06,>>,>>,>>,>>,>>,>>,9:28,>>,>>,>>,9:39

分解して格納使用かと考えたのですが調べても見つからず,学校ではrndくらいしかやってないので全くわかりません。
どなたか分解の仕方,またどう分解されるかなど教えていただけないでしょうか。
これはstrtokを使うと簡単に分解できますね。
http://www9.plala.or.jp/sgwr-t/lib/strtok.html
http://www1.cts.ne.jp/~clab/hsample/Func/Func08.html

Re: csvファイルからの取得

Posted: 2011年11月06日(日) 11:17
by kana
bitter_foxさん、アドバイスありがとうございます。



8:34,>>,>>,>>,>>,>>,9:06,>>,>>,>>,>>,>>,>>,9:28,>>,>>,>>,9:39
9:33,>>,>>,>>,>>,>>,10:00,>>,>>,>>,>>,>>,>>,10:23,>>,>>,>>,10:35
8:39,8:44,8:49,9:02,9:07,9:12,9:17,9:21,9:28,9:32,9:36,9:41,9:45,9:51,9:56,10:01,10:04,10:09
,,,,,,8:54,8:59,9:05,9:09,9:12,9:24,9:28,9:35,9:40,9:45,9:48,9:53

の各行をchに格納しstrtokを使ってみました

コード:

tp = strtok(ch, "," );
	if(tp != NULL || tp != ">>")
				sscanf(tp,"%d:%d",jikoku[0][0].hour,&jikoku[0][0].min);
else {		   jikoku[0][0].hour=NULL;
               jikoku[0][0].min=NULL;}
これを応用してforループで18*48行分格納できるよう繰り返させたかったのですが、
まず上記の最初の検出の際、どうも4行目の時刻のような場合は、,,,,,,を飛ばしていきなり8:54から検出されてしまいます.
ここではelseの方にひっかけたいのですが、どこを訂正したらいいでしょうか?

Re: csvファイルからの取得

Posted: 2011年11月06日(日) 14:40
by bitter_fox
kana さんが書きました:

コード:

tp = strtok(ch, "," );
	if(tp != NULL || tp != ">>")
				sscanf(tp,"%d:%d",jikoku[0][0].hour,&jikoku[0][0].min);
else {		   jikoku[0][0].hour=NULL;
               jikoku[0][0].min=NULL;}
これを応用してforループで18*48行分格納できるよう繰り返させたかったのですが、
まず上記の最初の検出の際、どうも4行目の時刻のような場合は、,,,,,,を飛ばしていきなり8:54から検出されてしまいます.
ここではelseの方にひっかけたいのですが、どこを訂正したらいいでしょうか?
NULLはポインタですので本来はポインタに対してのみ用いられるべきです。ですので、NULLをint型に代入するのは控えるべきです。
(恐らく0という意味で使ってるのかと思うのですが処理系によってはNULLが0でない可能性もあるのでよろしくありません)

それからjikokuを0で初期化しておけばelseに0を代入する文を入れる必要はなくなりますね。

あと、tp != ">>"はかなりの確率で真となってしまいますよ。
というのも、比較演算子は値の比較です。ですので、この際に比較しているのはtpのアドレスと">>"のアドレスを比較しているのであって中身を比較しているのではありません。
中身の比較にはstrcmpを用いてください。
http://www9.plala.or.jp/sgwr-t/lib/strcmp.html

本題のstrtokですが、strtok相当の,,を飛ばさない関数を作るか、strtokを実行する前に今変換してる物の末尾のアドレスを残しておいてstrtokの戻り値を比較することによって飛ばされた数を算出すればよいのではないでしょうか?

コード:

// _はヌル文字('\0')
+----------------+
|1234567890123454|
+----------------+
|8:54,,,16:24,...| // 元
+----------------+
|8:54_,,16:24,...|
|    ^           | // strtokを行う前に今変換している物の末尾(直近の\0)のアドレスを残しておく
+----------------+
|8:54___16:24,...| // strtok実行、戻り値は後ろの^に当たるところを指してる
|    ^  ^        | // 前の^と後の^を比較することで飛ばされた数を算出する
+----------------+
[hr][追記]sscanfの第二引数がポインタになっていませんよ
それからインデントをしっかりと行わないとバグの温床になってしまったり、何が書いてあるのか分からなくなったりするのでしっかりと行ってください。

Re: csvファイルからの取得

Posted: 2011年11月06日(日) 21:39
by box
,,,,,,8:54,8:59,9:05,9:09,9:12,9:24,9:28,9:35,9:40,9:45,9:48,9:53

1行読んだ後、中身をサーチして、上記のような場合は

>>,>>,>>,>>,>>,>>,8:54,8:59,9:05,9:09,9:12,9:24,9:28,9:35,9:40,9:45,9:48,9:53

に変換してからstrtokする、という方法はどうでしょうか。
変換するロジックは自分で考えないといけませんけれど。

Re: csvファイルからの取得

Posted: 2011年11月06日(日) 22:48
by naohiro19
C++であればBoost.tokenizerを使えばいいようです

Re: csvファイルからの取得

Posted: 2011年11月07日(月) 03:20
by かずま
scanf を使えばよいのでは?

コード:

#include <stdio.h>

#define N_COL 18
#define N_LINE 48

struct CELL { int hour, min; };

int get(struct CELL *p, FILE *fp)
{
    int c;
    p->hour = p->min = 0;
    fscanf(fp, "%d:%d", &p->hour, &p->min);
    while (c = getc(fp), c != EOF && c != ',' && c!= '\n') ;
    return c == EOF;
}

int main(void)
{
    struct CELL jikoku[N_LINE][N_COL];  int i, j, n;

    for (i = 0; i < N_LINE; i++)
        for (j = 0; j < N_COL; j++) {
            if (get(&jikoku[i][j], stdin)) break;
        }
    if (i < N_LINE) fprintf(stderr, "less data\n");
    n = i;
    for (i = 0; i < n; i++) {
        for (j = 0; j < N_COL; j++)
            printf(" %d:%02d", jikoku[i][j].hour, jikoku[i][j].min);
        printf("\n");
    }
    return 0;
}