C言語関係掲示板

過去ログ

No.151.カンマが2つ続いた場合のカラムの取り出し


No.976

CSV形式で問題が??
投稿者---プログラマー見習(2002/01/29 14:04:55)


ファイルに次のようなCSV形式のデータがあるとします。
社員番号、年齢、生年月日
11111,26,19760912
22222,,19761212
年齢は省略可能とします。
ファイルから一行ずつ読み込みカラムをstrtokで取得し二次元配列に
格納するとします。
すると一行目は正常に区切られるのですが、2行目の年齢が読み飛ばされて
生年月日がきてしまいます。二次元配列になにも値が入っていないものを
代入したいのですがうまくいきません。
どなたかご教授お願いします。

No.979

Re:CSV形式で問題が??
投稿者---B.Smith(2002/01/29 16:16:03)


こんにちは。

関数strtokは連続したセパレータをヌルに置き換えてしまいます。そのため、カンマが2つ続けて存在すると、それをトークンと見なしてくれません。
データを変えることはできないと思いますので、1つの項目に対し、必ずセパレータが一つだけ、とした関数strtokの代用処理を作成する必要があります。

文字列操作に関数strpbrkというのがあります。これは1番目の引数で指定するバッファ内から、2番目で指定した文字群に一致するものを探し、そのポインタを返します。この関数を利用すれば、簡単に代替処理を作成することができます。
サンプル.
#include <stdio.h>
#include <string.h>

void    Field(char *,char *);

void main(void )
{
    char    Test[] = "11111,26,19760912\n22222,,19761212";

    Field(Test,",\r\n");
}

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

    /* 文字列の末尾 */
    pEnd = pStr + strlen(pStr);

    while(1){
        /* セパレータの検索 */
        if (!(ptr = strpbrk(pStr,Sep))){
            /* セパレータが発見できなくても、ポインタが文字列の */
            /* 末尾に到達していない場合は、最後の文字列を処理す */
            /* るためループを終了しない                         */
            if (pStr >= pEnd)
                break;
            ptr = pEnd;
        }else
            *(ptr++) = 0;   /* セパレータをヌルにし、ポインタを移動 */

        /* 文字列の表示(切り出した項目の処理 */)
        printf("@:%s\n",pStr);

        /* 次の検索位置 */
        pStr = ptr;
    }
}




No.980
Re:CSV形式で問題が??
投稿者---プログラマー見習(2002/01/29 17:09:28)

>こんにちは。
>
>関数strtokは連続したセパレータをヌルに置き換えてしまいます。そのため、カンマが2つ続けて存在すると、それをトークンと見なしてくれません。
>データを変えることはできないと思いますので、1つの項目に対し、必ずセパレータが一つだけ、とした関数strtokの代用処理を作成する必要があります。
>
>文字列操作に関数strpbrkというのがあります。これは1番目の引数で指定するバッファ内から、2番目で指定した文字群に一致するものを探し、そのポインタを返します。この関数を利用すれば、簡単に代替処理を作成することができます。
><PRE>
サンプル.
#include <stdio.h>
#include <string.h>

void Field(char *,char *);

void main(void )
{
char Test[] = "11111,26,19760912\n22222,,19761212";

Field(Test,",\r\n");
}

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

/* 文字列の末尾 */
pEnd = pStr + strlen(pStr);

while(1){
/* セパレータの検索 */
if (!(ptr = strpbrk(pStr,Sep))){
/* セパレータが発見できなくても、ポインタが文字列の */
/* 末尾に到達していない場合は、最後の文字列を処理す */
/* るためループを終了しない */
if (pStr >= pEnd)
break;
ptr = pEnd;
}else
*(ptr++) = 0; /* セパレータをヌルにし、ポインタを移動 */

/* 文字列の表示(切り出した項目の処理 */)
printf("@:%s\n",pStr);

/* 次の検索位置 */
pStr = ptr;
}
}
</PRE>
>RESありがとうございます。
初心者でも理解できるレベルではコーディングできませんか。
お願いします。



No.981

Re:CSV形式で問題が??
投稿者---プログラマー見習(2002/01/29 17:42:29)


>>こんにちは。
>>
>>関数strtokは連続したセパレータをヌルに置き換えてしまいます。そのため、カンマが2つ続けて存在すると、それをトークンと見なしてくれません。
>>データを変えることはできないと思いますので、1つの項目に対し、必ずセパレータが一つだけ、とした関数strtokの代用処理を作成する必要があります。
>>
>>文字列操作に関数strpbrkというのがあります。これは1番目の引数で指定するバッファ内から、2番目で指定した文字群に一致するものを探し、そのポインタを返します。この関数を利用すれば、簡単に代替処理を作成することができます。
>><PRE>
>サンプル.
>#include <stdio.h>
>#include <string.h>
>
>void Field(char *,char *);
>
>void main(void )
>{
> char Test[] = "11111,26,19760912\n22222,,19761212";
>
> Field(Test,",\r\n");
>}
>
>void Field(char *pStr,char *Sep)
>{
> char *ptr,*pEnd;
>
> /* 文字列の末尾 */
> pEnd = pStr + strlen(pStr);
>
> while(1){
> /* セパレータの検索 */
> if (!(ptr = strpbrk(pStr,Sep))){
> /* セパレータが発見できなくても、ポインタが文字列の */
> /* 末尾に到達していない場合は、最後の文字列を処理す */
> /* るためループを終了しない */
> if (pStr >= pEnd)
> break;
> ptr = pEnd;
> }else
> *(ptr++) = 0; /* セパレータをヌルにし、ポインタを移動 */
>
> /* 文字列の表示(切り出した項目の処理 */)
> printf("@:%s\n",pStr);
>
> /* 次の検索位置 */
> pStr = ptr;
> }
>}
></PRE>
>>RESありがとうございます。
>初心者でも理解できるレベルではコーディングできませんか。
>お願いします。
>
ちなみに切り出した項目は空の項目も含めてポインタ配列に入れたいです。


No.982

Re:CSV形式で問題が??
投稿者---管理人(2002/01/29 18:28:20)


>>初心者でも理解できるレベルではコーディングできませんか。
>>お願いします。
>>
>ちなみに切り出した項目は空の項目も含めてポインタ配列に入れたいです。

ちょっと目に余りますので、横レス失礼します。

おそらく仕事でプログラムを作成していらっしゃると思いますので
敢えて苦言を呈します。
最初は誰しも初心者です。初心者から脱するには、ご自分で努力する
しか道はありません。
B.Smithさんが提示してくださるサンプルプログラム、本当にきれいで
ため息が出ます。ネットで見ず知らずの人に教授してもらえる環境は
昔はありませんでした。是非とも提示していただいたプログラムを
自分の物にしてください。

それから、本文引用は最低限にお願いします。また、投稿者名の統一も
お願いいたします。


No.985

Re:CSV形式で問題が??
投稿者---B.Smith(2002/01/29 19:33:16)


>初心者でも理解できるレベルではコーディングできませんか。

レベルに関係なく、プログラマーならばこの内容は決して難しいことではないはずなんですけど…
いくら私が分かりやすく回答したとしても、貴方が理解しようとしなければ、結局は単なる言葉のやり取りで終わってしまいます。
こちらとしても、可能な限りお力になれるよう努力はしますが、管理人さんも仰っているように、最終的には貴方自身が努力しなければ、何にもならないのです。

サンプルは、動作確認してあります(コメントは後で追加しました)。ポインタさえ理解できていれば、説明の必要は無いくらい簡単なものです。まず、じっくり読んでみてください。
分からないことは、別途質問してください。その時は「プログラム全体が分からない」というのではなく、「自分なりにこのように考えてみたのだが…」というような具体性を持った内容にしてくださいね。

どうしても理解できない場合は、ご自身で調べてみてください。ちょっと冷たいようですけど、調査能力はプログラマーには必須ですよ?また、問題点は分かっているはずですから、ご自分なりにアルゴリズムを作成しても良いのです。

掲示板上での質問・回答という性質上、必ずしも回答が即戦力になるとは限らないので、そこの所をご理解ください。基本的に参考資料にしかなり得ません。後は、プログラマーとしての貴方の腕の見せ所です。



問題点の方はご理解いただけましたでしょうか?

・関数strtokはカンマ(セパレータ)が連続すると、トークンとして切り出しません。
・関数strtokを使用するには、データとしてカンマが続かないようにする必要がありますが、そのためには、入力データを加工する必要があります。しかし、現実的には無理かもしれません。

そのために、トークン(項目)単位に、文字列を切り出す処理が必要になります。

このサンプルでは、セパレータ(カンマ、改行)を検索し、発見したらそれをヌルに置き換える、というstrtokもどきの処理を行っています。サンプル内の、以下の部分、
        /* 文字列の表示(切り出した項目の処理 */
        printf("@:%s\n",pStr);

pStrは項目の先頭位置を指しますので、項目毎の処理を記述すれば良いわけです。
pStrから一番近いセパレータはヌルに置き換えられていますので、そのまま文字列として扱うことができます。
ここではprintfを使用していますので、実行結果は、
@:11111
@:26
@:19760912
@:22222
@:
@:19761212

となります。カンマが2つ続いても、それを文字列長ゼロの文字列として扱うことができます。


戻る


「初心者のためのポイント学習C言語」 Last modified:2002.03.16
Copyright(c) 2000-2002 TOMOJI All Rights Reserved