C言語関係掲示板

過去ログ

No725 2バイト文字列が含まれる場合の検索

[戻る] [ホームページ]
No.8867

ファイルからの文字列検索
投稿者---KAI(2003/08/07 15:43:20)


皆様初めまして、KAIと申します。
C言語に関してはまだ未熟な者で、宜しかったらお力添え頂ければと思い掲示板に
投稿させて頂きました。


画面から指定する文字列を入力し、その文字列が既存のファイル(パス指定)に存在するかどうかのプログラムを考えております。

strstrを使って行うだろうと過去ログを参照したりしたのですが、1バイト文字と2バイト文字をどのように扱うのかが解らずに詰まっております。

例(予定) hogehoge 第一引数 第二引数
第一引数:検索ファイルへのパスとファイル指定
第二引数:検索文字列


環境
win2000Pro
vc++5.0

説明文が上手に書けず、解り難いかも知れませんが宜しくお願い致します。

No.8873

Re:ファイルからの文字列検索
投稿者---焼きたて(2003/08/08 10:52:18)


>画面から指定する文字列を入力し、その文字列が既存のファイル(パス指定)に存在するかどうかのプログラムを考えております。
>
>strstrを使って行うだろうと過去ログを参照したりしたのですが、1バイト文字と2バイト文字をどのように扱うのかが解らずに詰まっております。
>
>例(予定) hogehoge 第一引数 第二引数
>第一引数:検索ファイルへのパスとファイル指定
>第二引数:検索文字列
>
>
>環境
>win2000Pro
>vc++5.0
>
>説明文が上手に書けず、解り難いかも知れませんが宜しくお願い致します。

ひとつずつ考えていけば、難しいことはありませんよ。
まず、ファイルから1行ずつ読み込む。
その読み込んだ文字列と検索する文字列を、strstrを使って調べる。
NULL以外が帰ってきたら、文字列があったってことになるからwhile文を抜けて、見つかりましたとか表示して終了。
見つからなかったら、また次の1行を読み込んでしらべる。
最後の行まで調べても無かったら、見つかりませんませんでしたと表示。

もし関数の本とか持ってなかったら、ここを参考に。
tp://www.bohyoh.com/CandCPP/C/Library/index.html

No.8875

Re:ファイルからの文字列検索
投稿者---かずま(2003/08/08 11:31:07)


> strstrを使って行うだろうと過去ログを参照したりしたのですが、
> 1バイト文字と2バイト文字をどのように扱うのかが解らずに詰まっております。

2バイト文字が含まれる場合、単純に strstr を使うわけには行かないというのは
「Re:文字列から蠅箸いκ源が取り除けない。No.8865」にも書きました。

過去ログの http://f1.aaa.livedoor.jp/~pointc/log490.html が参考になるでしょう。

No.8876

Re:ファイルからの文字列検索
投稿者---KAI(2003/08/08 13:48:44)


KAIと申します。
投稿者です。

>焼きたてさん
レスありがとうございます。
検索文字列が1バイト文字なのか2バイト文字なのかを
先に判別してから検索をかけるべきなのか?等を考えておりました。

関数に関しては書籍ではないのですが、webから落としてきた関数表が
あるのですが、教えて頂いたサイトも活用させて頂きます。

>かずまさん
レスありがとうございます。

過去ログの「Re:文字列から蠅箸いκ源が取り除けない。No.8865」
に関しましては、投稿前に一度眼を通しております。

No.465.文章中から入力した文字列を探すプログラム
http://f1.aaa.livedoor.jp/~pointc/log465.html

No.376 ファイルを開き単語を検索
http://www3.realint.com/cgi-bin/tarticles.cgi?pointc2+376

あたりを読んだのですが、1バイト文字と2バイト文字の併用?
って点では理解を得られませんでした。

特殊な文字列は使わないのと、Windows環境下でしか使用しないので
JIS X 0208に準拠した環境での動作のみが保障されていれば問題ありません。


VBにて作成したプログラムには戻り値が無いので、その代わりに
log等で結果を吐かせて、そのlogファイルを検索して擬似的に戻り値を
与えようと思っております。

logに関してはどのような文字列(1バイトor2バイト)で正偽を判別するかは予測不能です。

C言語に関しては始めたばかりなので、関数表と睨めっこです。

検索文字列が1バイト文字か2バイト文字かって問題は余り気にしなくて
宜しいのでしょうか?

宜しくお願いいたします。


No.8877

Re:ファイルからの文字列検索
投稿者---なお(2003/08/08 15:47:10)


こんにちは。
面白そうなので、発言させていただきます。

確かに、strstrでは、上手く検索できないので、
ファイルから1文字ずつ読み取っていき、検索文字列の
最初の1文字と同じなら、検索文字の長さ回のループに入り、
さらに1文字ずつ読み取り、比較を行っていくという
形はどうでしょうか。

この形なら必要に応じて、最初の1文字に_ismbbtrailを
最後の一文字に_ismbblead等を使えば、
1バイト文字と、2バイト文字が混ざっていても大丈夫だと思います。


No.8878

Re:ファイルからの文字列検索
投稿者---YuO(2003/08/08 16:11:35)


>検索文字列が1バイト文字か2バイト文字かって問題は余り気にしなくて
>宜しいのでしょうか?

目的次第ですが,基本的には気にする必要があります。

確実なのは,検索する文字列及び検索される文字列をmbstowcsでワイド文字列に変換し,
wcschrなりwcsstrなりで検索をすることです。
ワイド文字は,一つの文字が二つ以上のwchar_tに分かれて表現されることはないですから。
#wcschrなら検索する文字はmbtowcで変換した方が効率的かも。

mblenで一文字の長さを計算しつつ,という方法もありますが……。


VC++にべったり依存してもよいのであれば,なおさんの書かれた_ismbbtrail, _ismbbleadや,
_mbschr, _mbsstrといった多バイト文字列対応の文字種テスト関数・文字列操作関数を使っても良いでしょう。


No.8880

Re:ファイルからの文字列検索
投稿者---焼きたて(2003/08/08 17:19:48)


ごめん。
1バイト、2バイトの問題のことが頭に無かった・・・。

自分で自作関数として実装するしかなさそうっすね。

<pre>int strstr_yakitate( const char *text1, const char *text2 )//text1がファイルの文字列、text2が検索したい文字列
{
//ここで、text2のほうが大きかったら処理打ち切っちゃてもいいね・・・実装してみて
	int i=0,count=0,flg=0;
	char c1[4]=&quot;あ&quot;,c2[4]=&quot;あ&quot;;


	while( text1[i] != '\0' ) { //文の最後でないとき
		printf(&quot;i=%d,count=%d\n&quot;,i,count);
		if( (unsigned char)text1[i] &gt;= 0x80 &amp;&amp; (unsigned char)text2[count] &gt;= 0x80) { //両方全角なら
			c1[0]=text1[i++];
			c1[1]=text1[i++];
			c2[0]=text2[count++];
			c2[1]=text2[count++];
			if( strcmp(c1,c2) != 0 ) { //等しくない場合、検索文字数を戻す
				count = 0;
				continue;
			}

			if(text2[count] == '\0') { //最後まで検索
					flg=1;
					break;
			}

			continue;
		}

		if( (unsigned char)text1[i] &lt;= 0x7F &amp;&amp; (unsigned char)text2[count] &lt;= 0x7F ) { //両方半角なら
			if(text1[i++] != text2[count++]) { //等しくない場合、検索文字数を戻す
				count = 0;
				continue;
			}

			if(text2[count] == '\0') {//最後まで検索
				flg=1;
				break;
			}

			continue;
		}
	}

	return flg;
}
</pre>


えー1時間かけた苦心作ですw
説明文とか少なくてごめんなさい。
もうへとへとで・・・

No.8881

Re:ファイルからの文字列検索
投稿者---焼きたて(2003/08/08 17:21:42)


c1[4]とc2[4]は、あを文字列として代入です。

No.8888

Re:ファイルからの文字列検索
投稿者---かずま(2003/08/09 23:22:31)


> 検索文字列が1バイト文字か2バイト文字かって問題は余り気にしなくて
> 宜しいのでしょうか?

検索されるほうのテキストが 1バイト文字か 2バイト文字かに注意し
て、きちんと文字境界で検索文字列と比較すれば、検索文字列のほう
が 1バイト文字か 2バイト文字かは気にしなくてよいでしょう。
#include <stdio.h>

#define isKanji(c)  (((c) & 0xFF ^ 0x20) - 0xA1u < 60)

char *find(const char *s1, const char *s2)
{
    for (; *s1; s1 += isKanji(*s1) ? 2 : 1) {
        const char *p1 = s1, *p2 = s2;
        do {
            if (*p2 == 0) return (char *)s1;
        } while (*p1++ == *p2++);
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    FILE *fp;  char buf[1024];

    if (argc != 3) return printf("usage: hogehoge file string\n"), 1;

    fp = fopen(argv[1], "r");
    if (fp == NULL) return printf("can't open %s\n", argv[1]), 1;

    while (fgets(buf, sizeof buf, fp))
        if (find(buf, argv[2])) break;
    puts(feof(fp) ? "not found" : "found");

    fclose(fp);
    return  0;
} 


No.8882

Re:ファイルからの文字列検索
投稿者---KAI(2003/08/08 18:09:43)


皆様ありがとうございます。
KAI@投稿者です。

>なおさん。
レスありがとうございます。

※参照サイト
http://www.microsoft.com/JAPAN/developer/library/vccore/_crt__ismbb_routines.htm
_ismbbtrail等の関数を勉強不足で知らなかったので調べてみました。
これはC++の環境に依存してしまいますよね(環境等に記述しなかった私に問題が
あります、すみません)
その前に、_ismbbtrail関数を絡めたループのロジックが思いつかないので
頭冷やして考えてみます。
選択の幅が広がったような気がします、ありがとうございます。


>YuOさん
レスありがとうございます。

※参照サイト
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/wcsstr.3.html
お恥ずかしい限りで、wcschr関数を良く知らなかったので調べて見ました。
上記サイトの説明文を読む限りですと、ちょっと感覚的に動きが解らないので
もう少し調べてからで無いとレスが出来ない状態です(解らないままレスをするのは
大変失礼なので)

沢山のヒントを頂いたような気がします、ありがとうございます。

>焼きたてさん。
レス&力作感謝です。

熟読して内容を理解してから、再度レスさせて下さい。
自分なりに勉強してからでないとレスが出来ません。

皆様ありがとうございます。
どのような形で実行させるかまだ解らないですが、色々調べて試してみます。
(余りにもC言語に関して無知なので、少しツライですが頑張ります)





No.8883

Re:ファイルからの文字列検索
投稿者---焼きたて(2003/08/08 19:20:11)


補足

まずちょっとバグってるよね。&quotとかいらないのは省いてね。

while文で、検索対象の文字列が最後まできたらwhileを終了します。
uhileの次のprintは、デバッグ用だったんではずしちゃってください(今、はずすの忘れて板の気づいた)。
最初のif文で検索対象文字列の該当文字、検索文字列の該当文字の両方が全角だったら、if文の中の処理をします。
なぜ0x80で全角文字とわかるかというと、0x00から0x7FまではASCIIコードが定義されています。
だからそれ以上の数値が入っていたら全角文字列だということです。
このif文の中の変な記号は、0x80以上だったらとしてください。
次に、c1,c2に全角文字を代入します。
全角文字列は、2バイトで格納されているので、2バイトコピーしています。
次にstrcmpで同じ文字列か比べています。
同じでなかったら、continueしてwhile文をやり直します。
もし検索文字のさいごまで一致していたなら、このwhile文を終了して、flgの1を返して、見つかったことを知らせます。

次のif文は、0x7F以下だったら半角文字列なので、両方半角文字列か比べています。