C言語関係掲示板

過去ログ

No.490.日本語を含むファイル内の文字列検索

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

日本語を含むファイル内の文字列検索
投稿者---203(2002/11/27 23:28:32)


ファイル内に日本語で指定した文字列が存在するかどうかを確認するプログラムはどう書けばよいのでしょうか?

宜しくお願い致します。


No.3612

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/11/28 02:31:52)


> ファイル内に日本語で指定した文字列が存在するかどうかを確認するプログラムは
> どう書けばよいのでしょうか?
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

#define BUF_SIZE 1024

int main(int argc, char **argv)
{
    wchar_t wbuf[BUF_SIZE], wcs[BUF_SIZE];

    if (argc != 2)
        return fprintf(stderr, "usage: %s string <file\n", argv[0]), 1;

    setlocale(LC_ALL, "");
    mbstowcs(wcs, argv[1], BUF_SIZE);

    while (fgetws(wbuf, BUF_SIZE, stdin))
        if (wcsstr(wbuf, wcs)) fputws(wbuf, stdout);
    return 0;
}


No.3629

Re:日本語を含むファイル内の文字列検索
投稿者---203(2002/11/28 17:50:03)


検索対象ファイル、検索文字はプログラム内で記述し、検索確認はあるかないかだけ表示するようにしたいのですが、どうすればよいでしょうか?

gccでコンパイルできるプログラムでお願いします。

No.3639

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/11/29 02:51:52)


> 検索対象ファイル、検索文字はプログラム内で記述し、検索確認はあるかないかだけ
> 表示するようにしたいのですが、どうすればよいでしょうか?

日本語の文字列検索とは無関係な C の基本事項ですが、お分かりになりませんか。

検索対象ファイルをプログラム内で記述するには、
stdin の代わりに、FILE *fp を用意し、fopen() を使う。C の基本ですね。

検索文字列をプログラム内で記述するには、
argv[1] の代わりに、その文字列を書くだけのことです。何が難しいのでしょうか。

検索確認をあるかないかだけ表示するようにするには、
fputws() の代わりに、puts("found"); と表示して終了すればよいし、while() を
抜けてしまったら、puts("not found") と表示すればよいのではありませんか。


> gccでコンパイルできるプログラムでお願いします。

Linux 7.2 の gcc 2.96 では、何の問題もなくコンパイルでき、実行できるんですが、
お使いの処理系はなんでしょうか。

No.3641

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/11/29 11:18:26)


> Linux 7.2 の gcc 2.96 では、何の問題もなくコンパイルでき、実行できるんですが、

Linux 7.2 は、RedHat Linux 7.2 のことです。
私の Windows 2000 に入れている Cygwin の gcc は、2.95.3-4 で、これには
fgetws などは入ってないようです。

fgetws などは、C の規格である ISO/IEC 9899:1993 (JIS X3010:1993) に
あとで追加された機能で、ISO/IEC は 1995年、JIS は 1996年です。
Borland C++ 5.5 や Visual C++ 6.0 には入っています。

No.3653

Re:日本語を含むファイル内の文字列検索
投稿者---203(2002/11/29 16:58:55)


私のgccはFreeBSD4.6のですが、fgetwsは対応してないようです。
gccのバージョンアップしてみます。
どもうもありがとうございました。

No.3658

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/11/29 19:33:11)


> 私のgccはFreeBSD4.6のですが、fgetwsは対応してないようです。

では、古い gcc や、LSI C-86 でも動くプログラムを書いてみましょう。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE  1024
#define FNAME     "file.txt"
#define STRING    "日本語"

#define SJIS  /* SJIS or EUC */

#ifdef SJIS
#define iskanji(c)  ((unsigned)((c) & 0xFF ^ 0x20) - 0xa1 < 60)
#endif

#ifdef EUC
#define iskanji(c)  ((c) & 0x80)
#endif

int mb_len(char *mb)
{
    if (iskanji(*mb)) return 2;
    if (*mb) return 1;
    return 0;
}

char *mbs_str(char *buf, char *str)
{
    int len;

    for (len = strlen(str); *buf; buf += mb_len(buf))
        if (memcmp(buf, str, len) == 0) return buf;
    return NULL;
}

int main(void)
{
    char buf[BUF_SIZE];
    FILE *fp = fopen(FNAME, "r");
    if (fp == NULL) return printf("can't open %s\n", FNAME), 1;

    while (fgets(buf, BUF_SIZE, fp))
        if (mbs_str(buf, STRING)) break;
    puts(feof(fp) ? "not found" : "found");
    return 0;
}


No.3664

Re:日本語を含むファイル内の文字列検索
投稿者---203(2002/11/30 14:13:07)


>では、古い gcc や、LSI C-86 でも動くプログラムを書いてみましょう。

ありがとうございます、助かりました。

No.3668

Re:日本語を含むファイル内の文字列検索
投稿者---あらら(2002/11/30 21:27:08)


<pre>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

#define BUF_SIZE 1024

int main(int argc, char **argv)
{
wchar_t wbuf[BUF_SIZE], wcs[BUF_SIZE];

if (argc != 2)
return fprintf(stderr, "usage: %s string <file\n", argv[0]), 1;

setlocale(LC_ALL, "");
mbstowcs(wcs, argv[1], BUF_SIZE);

while (fgetws(wbuf, BUF_SIZE, stdin))
if (wcsstr(wbuf, wcs)) fputws(wbuf, stdout);
return 0;
}
</pre>
 このプログラムってうまくいかないんだけど??
 mbstowcs(wcs, argv[1], BUF_SIZE)で、検索文字はマルチバイト文字からワイド文字に変換してるけど、対象ファイル内の文字はマルチバイト文字のままだからうまくいかないの気がします。

No.3669

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/11/30 22:38:03)


> このプログラムってうまくいかないんだけど??

うまくいかないとは、具体的にどういう状況なんでしょうか。
検索文字列は何ですか。
検索文字列が存在する行を表示しないんですか。
検索文字列が存在しない行を表示するんですか。

また、OS やコンパイラのバージョンなどの環境を示してください。
それから、使用している文字コードは何でしょうか。


> mbstowcs(wcs, argv[1], BUF_SIZE)で、検索文字はマルチバイト文字から
> ワイド文字に変換してるけど、対象ファイル内の文字はマルチバイト文字
> のままだからうまくいかないの気がします。

fgets ではなく、fgetws を使っていますから、対象ファイル内のマルチバイト
文字もワイド文字に変換されているはずですが。

No.3671

Re:日本語を含むファイル内の文字列検索
投稿者---あらら(2002/12/01 00:27:10)


>うまくいかないとは、具体的にどういう状況なんでしょうか。
>検索文字列は何ですか。
>検索文字列が存在する行を表示しないんですか。
>検索文字列が存在しない行を表示するんですか。


検索文字は「日本語」です。存在する行を表示しないという状況です。


>また、OS やコンパイラのバージョンなどの環境を示してください。
>それから、使用している文字コードは何でしょうか。


OSはred hat Linux7.3,コンパイラはgcc 2.96-110。使っている文字コードは7-bit JISです。

No.3672

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/12/01 14:07:45)


> OSはred hat Linux7.3,コンパイラはgcc 2.96-110。使っている文字コードは7-bit JISです。

私の手元にあるのは RedHat Linux 7.2 なので、断定は出来ませんが、7-bit JIS は、
多分だめだと思います。

locale -a | grep ja で、サポートされている locale を調べてみると、

ja_JP
ja_JP.eucjp
ja_JP.ujis
ja_JP.utf8
japanese
japanese.euc
japanese.sjis

環境変数 LANG にこれらの値を設定して、プログラム中で setlocale() を実行してみ
ると、"japanses.sjis" はエラーになり、実際にはサポートされていないようです。
"japanese.utf8" は、使えます。残りの locale は、すべて、文字コードが EUC です。

7-bit JIS というは、システムがサポートしていなくて、個々のコマンドで対応して
いるだけで、非常に使いづらいものだと思います。

たとえば、あららさんの gcc は 7-bit JIS 対応されていますか。
puts("あ"); をコンパイルできますか。
"あ" は、7-bit JIS で、1B 24 42 24 22 1B 28 42 です。
この中の 0x22 というのは、ASCII の " ですから、JIS 対応でないコンパイラは
そこで文字列が終わっていると解釈し、エラーになってしまいます。

7-bit JIS というのは、インターネット上で、情報交換をおこなうためには有用な
コードですが、UNIX 内部のコードとしては EUC の方が優れています。
だから、ja_JP や japanses も EUC となっているのでしょう。


No.3673

Re:日本語を含むファイル内の文字列検索
投稿者---あらら(2002/12/01 15:45:42)


> 私の手元にあるのは RedHat Linux 7.2 なので、断定は出来ませんが、7-bit JIS は、
> 多分だめだと思います。

その通りでした。
文字コードをEUCに変えてみたら、ちゃんと動作するようになりました。
いろいろ教えてくださってありがとうございます。

No.3674

Re:日本語を含むファイル内の文字列検索
投稿者---かずま(2002/12/01 22:19:14)


> "japanese.utf8" は、使えます。残りの locale は、すべて、文字コードが EUC です。

訂正します。"japanese.utf8" ではなく、"ja_JP.utf8" ですね。

余談ですが、UTF-8 についてちょっと書いてみます。

UTF-8 では、"あ" は、E3 81 82 の 3バイトになります。EUC の A4 A2 や、Shift-JIS の
82 A0 に比べて、無駄なように思われますが、UTF-8 には、すぐれた特徴があります。

それは、EUC や SJIS が日本語(と英語)しか扱えないのに対して、世界中の文字を同時
に扱えることです。また、ASCII がそのまま 7ビット 1バイトであり、2バイト以上の文字も、
先頭バイトが C2〜EF で、後続のバイトが 80〜BF なので、文字の境界を間違えること
がないということです。

どういうことかというと、システムの文字コードが UTF-8 だと
    while (fgets(buf, sizeof buf, stdin))
        if (strstr(buf, argv[1])) fputs(buf, stdout);
これで、文字列の検索が出来てしまうのです。

EUC だと、"イあ" が A5 A4 A4 A2 になりますから、これがファイルにあると、
検索文字 "い" の A4 A4 がマッチしてしてしまいます。

SJIS にも同様の問題がある上、さらに 2バイト目が 40〜7E になることもあるので、
ASCII との重なりも問題になります。

それから、Linux も Windows も、wchar_t が Unicode (ISO 10646 の UCS-2) になって
いますが、これと UTF-8 との変換は、変換テーブルによらず、簡単なビット演算ででき
てしまうことからも UTF-8 は有利です。もっともシステムがちゃんとサポートしてい
て、すべてのコマンドが UTF-8 を扱えるようになっていないとダメですが。