csvファイルからの取得

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kana

csvファイルからの取得

#1

投稿記事 by kana » 14年前

アルゴリズムの授業で出された課題で,
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くらいしかやってないので全くわかりません。
どなたか分解の仕方,またどう分解されるかなど教えていただけないでしょうか。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

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

#2

投稿記事 by bitter_fox » 14年前

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

kana

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

#3

投稿記事 by kana » 14年前

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の方にひっかけたいのですが、どこを訂正したらいいでしょうか?

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

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

#4

投稿記事 by bitter_fox » 14年前

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の第二引数がポインタになっていませんよ
それからインデントをしっかりと行わないとバグの温床になってしまったり、何が書いてあるのか分からなくなったりするのでしっかりと行ってください。

box
記事: 2002
登録日時: 15年前

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

#5

投稿記事 by box » 14年前

,,,,,,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する、という方法はどうでしょうか。
変換するロジックは自分で考えないといけませんけれど。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

naohiro19
記事: 256
登録日時: 15年前
住所: 愛知県

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

#6

投稿記事 by naohiro19 » 14年前

C++であればBoost.tokenizerを使えばいいようです

かずま

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

#7

投稿記事 by かずま » 14年前

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;
}

閉鎖

“C言語何でも質問掲示板” へ戻る