C言語関係掲示板

過去ログ

No.116.特定の文字列を含むデータをすべて取り出す


No.659

比較関数
投稿者---めろんぱん(2001/12/08 21:58:18)


こんばんは。
リストの中から、ある文字を含むデータをすべてとりだしたいです。
strcmpだと、1つのデータしかとりだせないので、
なにかいい方法、または関数はないのでしょうか。
お願いします。


No.660

Re:比較関数
投稿者---shu(2001/12/08 22:48:54)
http://c2c-1.rocketbeach.com/~finder_s/ccc/


>こんばんは。
>リストの中から、ある文字を含むデータをすべてとりだしたいです。
>strcmpだと、1つのデータしかとりだせないので、
>なにかいい方法、または関数はないのでしょうか。
>お願いします。

リストの数と同じ分配列をって、データ内に文字があれば 1(TURE)
無ければ 0(FALSE) にのようにチェックして、後から 1(TURE)の
データだけを取り出すっていうのはどうですか?



No.661

Re:比較関数
投稿者---B.Smith(2001/12/08 23:55:08)


こんばんは。

私の方から標準ライブラリを使用した方法について一言。

文字列操作関数にstrstrというものがあります。

char *strstr(const char *BaseStr,const char *FindStr);

この関数は、BaseStr内からFindStrで指定した文字列を検索します。発見した場合、その位置のポインタを返し、発見できなかった場合NULLを返します。

例えば、バッファString内に"Have a nice day."という文字列を格納しているとします。このバッファ内の文字列に"nice"が含まれているか検査しなければならない場合、関数strcmp(またはstrcmpi)を使用した時はバッファString内のすべての文字列が一致しなければ真になりませんが、関数strstrを使用した場合、"nice"を含むすべての文字列が真(ポインタを返す)になります。
    if (strstr(String,"nice")){
        (発見時の処理)
    }

汎用の標準ライブラリ関数は使い方次第では大変便利なのですが、このような比較的単純な操作の場合、繰り返し行われると、関数のオーバヘッドのため速度効率が悪くなります。1回の検索に長い文字列が参照される場合には、この関数を使用するのが適当ですが、検索するデータが多量にある場合(検索する回数が多い場合)や、少しでも処理を早くしたい場合は、shuさんが解説してくださった、配列を使う方法を組み込んでしまった方が、速度効率的には断然有利です。




No.663

Re:比較関数
投稿者---めろんぱん(2001/12/09 00:16:57)


>文字列操作関数にstrstrというものがあります。
>
> char *strstr(const char *BaseStr,const char *FindStr);
if (strstr(String,"nice")){
(発見時の処理)
}
では、Stringの中身が、nice and nice purus good nice(笑)
などというときには、niceすべて(3つ)のポインタが返るのでしょうか?
どのような方法でもよいので、一致した結果をすべて表示させたいのです。
また、フラグの方法についてですが、一度やろうと思い、うまくいかなかった
(自分の能力不足です)ため、フラグを使わない方法でやりたいのですが。
shuさん、すみません。ありがとうございました。

No.664

Re:比較関数
投稿者---B.Smith(2001/12/09 00:55:19)


検索対象文字列が複数ある場合、その数だけポインタが返るのか…ということですが、組み方によってはできます。
例1

    static char *TestBuf = "This is Example.";
    char        *ptr;

    while(1){
        /* "is"の検索 */
        ptr = strstr(ptr,"is");

        /* 文字列を発見しなかったらループを終了 */
        if (!ptr)
            break;

        /* 結果を表示 */
        printf("%s\n",ptr);

        /* 現在のポインタは発見時の位置にあるので、 */
        /* ポインタを"is"分進める                   */
        /* 注意:これが無いと無限ループになります   */
        ptr += 2;
    }

例1では"This is Example."の中から"is"を検索します。TestBuf内には"is"が2つあるので、
is is Example.
is Example.

という結果になります。
これは推測なので、もし間違っていたら指摘していただきたいのですが、「一致した結果をすべて表示させたい」、ということですから、恐らく、対象の文字列内に一箇所でも検索対象を発見した場合、「その文字列は発見したと見なされる」という意味だと思います。そして、その文字列をすべて表示したい…GREP機能を作る際のアルゴリズムの一部です。
例2
#include <stdio.h>
#include <string.h>

void main(void )
{
    static char     *TestBuf[] = {
        "本日は晴天なり",
        "先日食ったふぐの刺身は美味かった",
        "二日酔いの朝の水に勝るものなし",
        "食って食って食いまくった",
        NULL
    };
    char    **ptr;

    ptr = TestBuf;

    /* TestBuf内のすべての文字列を検索する */
    while(*ptr){
        /* "食っ"を含む文字列を表示する */
        if (strstr(*ptr,"食っ"))
            printf("%s\n",*ptr);

        ptr++;  /* 次の文字列 */
    }
}

例2はTestBuf内にあるすべての文字列を"食っ"で検索し、一箇所でも"食っ"が入っていれば、その文字列を表示します。上記の例の実行結果は、
先日食ったふぐの刺身は美味かった
食って食って食いまくった

が表示されます



No.667

Re:比較関数
投稿者---B.Smith(2001/12/09 01:16:18)


すいません。例1に代入が抜けていました。whileの直前です。

例1

    static char *TestBuf = "This is Example.";
    char        *ptr;

    ptr = TestBuf;    /* ← 申し訳ないです */

    while(1){
        /* "is"の検索 */
        ptr = strstr(ptr,"is");

        /* 文字列を発見しなかったらループを終了 */
        if (!ptr)
            break;

        /* 結果を表示 */
        printf("%s\n",ptr);

        /* 現在のポインタは発見時の位置にあるので、 */
        /* ポインタを"is"分進める                   */
        /* 注意:これが無いと無限ループになります   */
        ptr += 2;
    }




No.668

Re:比較関数
投稿者---めろんぱん(2001/12/09 08:46:50)


ありがとうございます。
では、探したい文字列が構造体配列の場合、それらを全部
TestBuf[]にいれてやるのでしょうか?
文字数はけっこうありますが。

No.669

Re:比較関数
投稿者---B.Smith(2001/12/09 11:11:28)


おはようございます。

検索したい文字列が構造体内にある場合でも考え方は同じです。方法はいろいろありますが、データがメモリ上にすべて収まっている場合は、直に構造体にアクセスした方が効率的でしょうね。
例.
#include <stdio.h>
#include <string.h>

typedef struct  {
    char    Key[100+1];
    int     Data1;
    int     Data2;
}EX_STRUCT,*PEX_STRUCT;

void main(void )
{
    static EX_STRUCT    TestData[] = {
        "千葉太郎",100,10,
        "東京太郎",200,20,
        "栃木太郎",300,30,
        "埼玉花子",400,40,
        "神奈川花子",500,50,
        "群馬花子",600,60,
        "",-1,-1    /* 番人を-1とする */
    };
    PEX_STRUCT  pTbl;

    pTbl = TestData;

    /* TestData内のすべての文字列を検索する */
    while(pTbl->Data1 >= 0){

        /* "太郎"を含むデータをすべて表示 */
        if (strstr(pTbl->Key,"太郎"))
            printf("%s   %d   %d\n",
                pTbl->Key,pTbl->Data1,pTbl->Data2);

        pTbl++;  /* 次の要素 */
    }
}

この結果は、
千葉太郎   100   10
東京太郎   200   20
栃木太郎   300   30

となります。


No.670

Re:比較関数
投稿者---めろんぱん(2001/12/09 12:12:53)


おはようございます。

自分のプログラムの中でいろいろやってみたのですがうまくいきません。
構造体、ポインタ、配列、関数などが一緒になると、
さっぱりという感じで。
ソースをみてほしいのですが、メールで送るというのはだめでしょうか?


No.671

Re:比較関数
投稿者---B.Smith(2001/12/09 12:59:21)


>ソースをみてほしいのですが、メールで送るというのはだめでしょうか?

う〜ん…情報の公開・知識の共有、という意味ではルール違反なのですが、掲示板に全ソースを載せるわけにはいきませんし……

急ぎの場合等、本気でお困りの時には、私はかまいませんよ?いつでもどうぞ。

しかし、基本的には、先に申し上げた通り、掲示板は「情報の公開・知識の共有」が前提です。出来れば、問題点をご自分で洗い出し、掲示板上で解決するのがベストです。その方が、いろいろな方々の御意見を聞くこともできますしね。



No.665

Re:比較関数
投稿者---kikk(2001/12/09 01:02:00)


ども。


以下のようなかんじでしょうか。

p=str;
len=strlen(str);
while ((p=strstr(p,"nice"))!=NULL) {
/* 見つかったときの処理 */
/* pが見つかった位置へのポインタ */
/* p-strで何文字目で見つかったかが得られる */

/* 検索開始位置の更新 */
p+=len;
if (*p=='\0')
 break;
}


Cでは複数の値を返す方法はありません。それと同じようなことを実現するには、
構造体を返すか、複数のデータが格納されている場所へのポインタ(つまり配列
ないし構造体へのポインタ)を返すというようにします。あるいは、返り値で
結果を得るという方法にこだわらなければ、結果格納用の領域へのポインタを
あらかじめ引き渡しておき、そこに結果を書き込んでもいいかもしれません。


では。

No.666

Re:比較関数
投稿者---kikk(2001/12/09 01:13:28)


ども。

ちょっと修正。

>if (*p=='\0')
> break;

は冗長で、なくていいです(あっても結果は出ますが、ない方が効率的)。

けっきょく、B.Smithさんのと同じですね。。


では。


戻る


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