掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.30118

ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---べた(2007/05/12 13:20:01)


ファイルから1行ずつ読込、カンマが2つ以上続いた
カラムの取り出しをしています。

ここで、末尾がカンマで終わっている場合と値がある場合
とで表示の仕方が変わってくるのです。
カンマが存在した場合、ヌルに置き換えているのですが、
末尾がカンマで終わっている場合は、その部分がヌルで
表示されません。

「・・・・,0.0」
「・・・・,0,」

前者の場合は、
0:xxx
1:xxxxxx
:
8:
9:0
10:0
となるのですが、

後者の場合は、
0:xxx
1:xxxxx
:
8;
9:0
となり、最後の状態が表示されません。
最後もヌルで表示したいのでがどうすればよいのですか。
(拙い文章ですみません。)

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

void Field(char *,char *);

main()
{
    FILE *fp;
    char buff[256];

    fp = fopen("test.csv","r");

    while(fgets(buff,sizeof buff,fp) != NULL) {
        buff[strlen(buff)-1] = '\0';

        printf("buff : [%s]\n",buff);
        Field(buff,",");

    }

    fclose(fp);
}

void Field(char *pStr,char *Sep)
{
    char *ptr,*pEnd;
    int i;

    pEnd = pStr + strlen(pStr);

    i = 0;
    while(1){
        if (!(ptr = strpbrk(pStr,Sep))){
            if (pStr >= pEnd)
                break;
            ptr = pEnd;
        }else
            *(ptr++) = 0;

        printf("%2d : %s\n",i++,pStr);

        pStr = ptr;
    }
}





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて 30122 RAPT 2007/05/12 20:45:23
<子記事> Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて 30127 yoh2 2007/05/13 02:33:29


No.30122

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---RAPT(2007/05/12 20:45:23)
http://blogs.wankuma.com/rapt/


カンマ区切りにしたいだけなら、strchr を使った方が
取り回しが楽かも。

あと、具体的にどんなデータを与えた時、どう表示してほしいか、
省略せずにサンプルを書いてもらえないと、何がしたいか伝わりません。

「最後の状態」って一体何?
「最後もヌルで表示したい」何を意図している?



この投稿にコメントする

削除パスワード

No.30127

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---yoh2(2007/05/13 02:33:29)


入力例の前半が省略されていて、出力例とうまく対応付けができないのですが、つまり
入力: "abc,def,hogegohe,123,456"
出力:
    0:abc
    1:def
    2:hogehoge
    3:123
    4:456

入力: "abc,def,,123,"
出力:
    0:abc
    1:def
    2:
    3:123
    4:
となって欲しいところが、後者の出力が
    0:abc
    1:def
    2:
    3:123   ("4:"が出力されない)
となってしまう、ということでしょうか? (0〜10は長くなりすぎますので0〜4にしました)

で、この前提で話を進めます。

関数Field中で、Sep中の文字が見付からなかった場合にやや面倒な処理をしていますが、
これが裏目に出ていますね。
今の形をできるだけ保ったまま修正するとなると、こんな具合でしょうか。
    /* Field()中のwhileループを以下のように変更。 
     * ここより前にあるpEndも不要になるので削除しましょう。 */
    while(ptr){
        /* Sep中の文字が見付からない場合は特に何もしない。
         * 変更したループ条件が不成立になるので、pirntf()後に
         * ループを抜けることになる。 */
        if ((ptr = strpbrk(pStr,Sep)) != NULL){
            *(ptr++) = 0;
        }
        printf("%2d : %s\n",i++,pStr);

        pStr = ptr;
    }

ところで些細なつっこみをふたつ。

その1: #include <string.h>が抜けている
strpbrk()は<string.h>で宣言されている関数です。

その2: 末尾の改行削除について(これは的外れかも)
>    while(fgets(buff,sizeof buff,fp) != NULL) {
>        buff[strlen(buff)-1] = '\0';
入力ファイルの書式定義にもよりますが、もし、最後の行の末尾に改行がない場合も許すなら
その最後の行が壊れますね。最後の文字が'\n'なら'\0'に書き換える、とした方がよいかも。


この投稿にコメントする

削除パスワード

No.30128

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---べた(2007/05/13 11:26:49)


RAPTさん、yoh2さん
ありがとうございます。また、説明不足で申し訳ありません。
期待している結果は、yoh2さんが述べて頂いたことです。

--データ
abc,efg,hij,klm,opq
1,,,,2
a,,,,
,1,2,3,4
123,456,789,0,
a,b,c,d,e

データの終わりが、カンマとなっている場合
「a,,,,」とか「123,456,789,0,」ですが、
本来、
「a,,,,」
0 : a
1 :
2 :
3 :
4 :

「123,456,789,0,」
0 : 123
1 : 456
2 : 789
3 : 0
 4 :
としたいのですが、
「a,,,,」
0 : a
1 :
2 :
3 :

「123,456,789,0,」
0 : 123
1 : 456
2 : 789
3 : 0

となり、「4:」が出力されないということです。

以下の通りにしましたら上手くいきました。
ただ、ファイルの中身(データ)が2行以上あると表示が行われ
ませんでした。
「Field関数」内で使用している「ptr変数」が2回目以降だと
ヌルとなるためみたいです。
「ptr = pStr」のようにしました。よいのでしょうか。

>その2: 末尾の改行削除について(これは的外れかも)
>
> while(fgets(buff,sizeof buff,fp) != NULL) {
> buff[strlen(buff)-1] = '\0';
を外すと、ループが1回余分に実施されます。
つまり、「5:」が表示されるのですが、この場合、どうしたら
よいのでしょうか。


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

void Field(char *,char *);

main()
{
    FILE *fp;
    char buff[256];

    fp = fopen("test.csv","r");

    while(fgets(buff,sizeof buff,fp) != NULL) {
        buff[strlen(buff)-1] = '\0';

        printf("buff : [%s]\n",buff);
        Field(buff,",");

    }

    fclose(fp);
}

void Field(char *pStr,char *Sep)
{
    char *ptr;
    int i;


    ptr = pStr;

    i = 0;
    while(ptr){
        if ((ptr = strpbrk(pStr,Sep)) != NULL){
            *(ptr++) = 0;
        }

        printf("%2d : %s\n",i++,pStr);

        pStr = ptr;
    }
}




この投稿にコメントする

削除パスワード

No.30129

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---RAPT(2007/05/13 13:14:09)
http://blogs.wankuma.com/rapt/


> buff[strlen(buff)-1] = '\0';

if ( strlen(buff) > 0 && buff[strlen(buff)-1] = '\n' ) {
    buff[strlen(buff)-1] = '\0';
}




この投稿にコメントする

削除パスワード

No.30130

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---yoh2(2007/05/13 13:19:18)


>ただ、ファイルの中身(データ)が2行以上あると表示が行われ
>ませんでした。
>「Field関数」内で使用している「ptr変数」が2回目以降だと
>ヌルとなるためみたいです。
>「ptr = pStr」のようにしました。よいのでしょうか。

あ、それは私のミスですorz
確かにptrの初期化が必要ですね。

# いや、最初はdo-whileで組んでたもんで。
# whileに直す時にptrの初期値を入れるのをうっかり忘れとりました。


>>その2: 末尾の改行削除について(これは的外れかも)
>>
>> while(fgets(buff,sizeof buff,fp) != NULL) {
>> buff[strlen(buff)-1] = '\0';
>を外すと、ループが1回余分に実施されます。
>つまり、「5:」が表示されるのですが、この場合、どうしたら
>よいのでしょうか。

外すって、
>>> buff[strlen(buff)-1] = '\0';
を無条件に削除したということですか?
前回の投稿で、

> 最後の文字が'\n'なら'\0'に書き換える、とした方がよいかも。

と書いた通り、buff[strlen(buff)-1] == '\n'ならそこに'\0'を代入、’\n'で
なければ何もしない、とした方がいいのでは? という指摘だったのですが。

とはいえ、それで余分な"5:"が出力されるというのは変ですね。
例えば、入力が"a,b,c,d"の場合、出力の最後のひとつが
"4:d"
の代わりに、
"4:d
" ←"d"の直後に余分な改行が付く
となるハズなんですが……
main()で、Fieldで指定している第2引数が",\n"ならば話は別ですが。


この投稿にコメントする

削除パスワード

No.30133

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---べた(2007/05/14 18:39:12)


説明不足ですみません。

外すというのは、
buff[strlen(buff)-1] = '\0';
の処理を行わないというこです。

「5:」が出力されるのではなく、
改行(ゴミ行)が表示されます。
[abc,efg,hij,klm,opq]
0 : abc
1 : efg
2 : hij
3 : klm
4 : opq
←改行(ゴミ行)が出力される。
[1,,,,2]
0 : 1
1 :
2 :
3 :
4 : 2
←改行(ゴミ行)が出力される。
>main()で、Fieldで指定している第2引数が",\n"ならば話は別ですが。
とすると、「5:」が出力されます。

[abc,efg,hij,klm,opq]
0 : abc
1 : efg
2 : hij
3 : klm
4 : opq
5 :
[1,,,,2]
0 : 1
1 :
2 :
3 :
4 : 2
5 :

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

void Field(char *,char *);

main()
{
    FILE *fp;
    char buff[256];

    fp = fopen("test.csv","r");

    while(fgets(buff,sizeof buff,fp) != NULL) {

        printf("buff : [%s]\n",buff);
//        Field(buff,",");
        Field(buff,",\n");

    }

    fclose(fp);
}

void Field(char *pStr,char *Sep)
{
    char *ptr;
    int i;

    ptr = pStr;
    i = 0;
    while(ptr){
        if ((ptr = strpbrk(pStr,Sep)) != NULL){
            *(ptr++) = 0;
        }

        printf("%2d : %s\n",i++,pStr);

        pStr = ptr;
    }
}




この投稿にコメントする

削除パスワード

No.30135

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---RAPT(2007/05/15 00:44:55)
http://blogs.wankuma.com/rapt/


そりゃそうだ。
問題は while の条件式。
> while( ptr )
では、ptr が NULL かどうかしかチェックしておらず、文字列の終端か
どうかのチェックができないため、最後の改行が処理されています。



この投稿にコメントする

削除パスワード

No.30136

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---yoh2(2007/05/15 01:51:27)


あぁ、ちょっとした突っ込みのつもりが、説明のマズさと余計な一言でどんどん
深みに嵌っていく……

>>main()で、Fieldで指定している第2引数が",\n"ならば話は別ですが。
>とすると、「5:」が出力されます。

ええと、これ、第2引数に",\n"すべきだ、ということを暗に述べているわけではなく、
",\n"とでもしない限り、「5:」が出力されるような事態にならないんだけどなぁ、
と、ちと不可解な状況を愚痴った、いわば「余計な一言」でした。
正常に動作するコードを書くという目的のためには、とりあえず",\n"については
忘れておいてください。Fieldの第2引数は","で正解です。

ではどうしたらよいか。
これは三度載せますが、

> 最後の文字が'\n'なら'\0'に書き換える、とした方がよいかも。

こいつをCに書き下して下さい。
buff[strlen(buff)-1] = '\0';を無条件に実行するのも、全部削除してしまうのもNG。
具体的には、別枝でRAPTさんが載せたソースほぼそのまま。
('='と'=='のtypoだけ修正しています)
if ( strlen(buff) > 0 && buff[strlen(buff)-1] == '\n' ) {
    buff[strlen(buff)-1] = '\0';
}
# fgetsの仕様上、buffが空文字列にならない (strlen(buff) > 0 のチェック不要)
# 気がしますが…… ← む、これも「余計な一言」か……


この投稿にコメントする

削除パスワード

No.30140

Re:ファイルからカンマが2つ以上続いたカラムの取り出しについて
投稿者---べた(2007/05/16 16:46:26)


RAPTさん、yoh2さん
ありがとうございます。

同じような質問を何度も致し、同じ説明を3度も頂くような
ことを致し、お手間をおかけしました。

>buff[strlen(buff)-1] = '\0';を無条件に実行するのも、全部削除してしまうのもNG。
>
>if ( strlen(buff) > 0 && buff[strlen(buff)-1] == '\n' ) {
> buff[strlen(buff)-1] = '\0';
>}

を組み込み、期待した結果を得られました。




この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧