検索

2009-10-26 3 views
5

次のコードは、1つの文字の時にテキストファイルを読み込み、標準出力にそれを印刷:検索

#include <stdio.h> 

int main() 
{ 
    char file_to_open[] = "text_file.txt", ch; 
    FILE *file_ptr; 

    if((file_ptr = fopen(file_to_open, "r")) != NULL) 
    { 
     while((ch = fgetc(file_ptr)) != EOF) 
     { 
      putchar(ch); 
     } 
    } 
    else 
    { 
     printf("Could not open %s\n", file_to_open); 
     return 1; 
    } 
    return(0); 
} 

しかし、その代わりに印刷をstdoutに[のputchar(CH)]私がしたいです別のテキストファイルで提供されている特定の文字列、すなわちファイルを検索します。 strings.txt出力

text_file.txt

をout.txtをするマッチの行:

 
1993 - 1999 Pentium 
1997 - 1999 Pentium II 
1999 - 2003 Pentium III 
1998 - 2009 Xeon 
2006 - 2009 Intel Core 2 

strings.txt:この場合

 
Nehalem 
AMD Athlon 
Pentium 
text_file.txt

の3つの第1行は一致します。私はCでのファイル操作に関するいくつかの研究を行ってきましたが、fgetc(私のコードのように)、1行にfgets、1ブロックにfreadという文字を読むことができます私の状況で完璧だろうか?

+3

なぜあなたはこのプログラムを書いています!これを行うには、grep/awk/sedを使用してください。 –

+0

いいえ、Tim。タグは検索用です。誰もそれを探すつもりはない。 – GManNickG

+1

はい、私はこれを数秒で解決できる標準のUnixツールを知っていますが、これはCファイルIOの深い理解を得ることです。 –

答えて

7

私はこれが学習の練習であると仮定しており、単に開始する場所を探しています。それ以外の場合は、ホイールを改造しないでください。

以下のコードは、何が関係しているかを示すものです。これは、検索するファイルの名前と、そのファイルを検索する単一の引数を指定できるプログラムです。これを修正して、フレーズを文字列の配列で検索し、その配列内の単語のいずれかが読み込まれた行のいずれかに現れるかどうかを確認する必要があります。

お探しの主要機能はstrstrです。

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

#ifdef DEBUG 
#define INITIAL_ALLOC 2 
#else 
#define INITIAL_ALLOC 512 
#endif 

char * 
read_line(FILE *fin) { 
    char *buffer; 
    char *tmp; 
    int read_chars = 0; 
    int bufsize = INITIAL_ALLOC; 
    char *line = malloc(bufsize); 

    if (!line) { 
     return NULL; 
    } 

    buffer = line; 

    while (fgets(buffer, bufsize - read_chars, fin)) { 
     read_chars = strlen(line); 

     if (line[read_chars - 1] == '\n') { 
      line[read_chars - 1] = '\0'; 
      return line; 
     } 

     else { 
      bufsize = 2 * bufsize; 
      tmp = realloc(line, bufsize); 
      if (tmp) { 
       line = tmp; 
       buffer = line + read_chars; 
      } 
      else { 
       free(line); 
       return NULL; 
      } 
     } 
    } 
    return NULL; 
} 

int 
main(int argc, char *argv[]) { 
    FILE *fin; 
    char *line; 

    if (argc != 3) { 
     return EXIT_FAILURE; 
    } 

    fin = fopen(argv[1], "r"); 

    if (fin) { 
     while (line = read_line(fin)) { 
      if (strstr(line, argv[2])){ 
       fprintf(stdout, "%s\n", line); 
      } 
      free(line); 
     } 
    } 

    fclose(fin); 
    return 0; 
} 

出力例:

 
E:\Temp> searcher.exe searcher.c char 
char * 
    char *buffer; 
    char *tmp; 
    int read_chars = 0; 
    char *line = malloc(bufsize); 
    while (fgets(buffer, bufsize - read_chars, fin)) { 
     read_chars = strlen(line); 
     if (line[read_chars - 1] == '\n') { 
      line[read_chars - 1] = '\0'; 
       buffer = line + read_chars; 
main(int argc, char *argv[]) { 
    char *line; 
+0

これは非常に興味深いようです。あなたは正しく仮定しています、これは私のための学習の練習です、そして、私は、以前に働いていた要素で構成されていることがわかります。このコードを完全に理解できるはずです。 –

+0

私はかなり新しいCコードですが、fgets関数呼び出しでread_line関数呼び出し全体を置き換え、fgetsが '\ n'文字で終了するので、main関数のchar *行を任意の数に割り当てました。おそらく、read_line関数の目的を説明できますか?余分なコードがたくさんあるようです。 – anon58192932

+1

@advocate [大きさはどれくらい大きいですか?](http://en.wikipedia.org/wiki/Buffer_overflow)合理的なサイズのバッファから始め、必要に応じて拡大していきます。実際にはバッファが大きすぎてコンピュータがメモリを使い果たしてしまうのを防ぐもう一つのチェックが必要です。 –

4

注意:fgetc()、getc()、getchar()はすべてcharではなく整数を返します。整数はEOFか有効な文字ですが、char型でサポートされている範囲より1つ多くの値を返します。あなたは「fgrepは」コマンドの代理を書いている

fgrep -f strings.txt text_file.txt > out.txt 

代わりの文字を読んで、あなたはラインを読む必要がしようとしている - のfgets()を使用します。 (gets()関数が存在するのを忘れてください)

あなたのコードをインデントしてリターン0を挿入しました。 (あなたがmain()の終わりから落ちるならば、C99は暗黙の 'return 0;'を行います)。しかし、C99はまた、すべての関数に明示的な戻り値の型を要求しています。int intをintに追加しました。エラーメッセージは、標準出力ではなく標準エラーに書き込まれるべきです。

おそらく、文字列のリストに動的割り当てを使用する必要があります。簡単な検索では、各入力行に必要な各文字列を検索するために 'strstr()'を適用します(一致を見つけたらループを解除するようにします。 1行で)。

より洗練された検索では、どの文字を無視することができるので、すべての文字列を並行して検索し、ループインループよりも速くスキップすることができます。これは、Boyer-MooreやKnuth-Morris-Pratt(が追加された:または複数の文字列をパラレル検索するために設計されたRabin-Karp)などの検索アルゴリズムの変更です。

+0

私は個人的に文字をバッファリングする関数を書いています... fgetsだけを使うと、行の長さに任意の制限が与えられます。 – asveikau

+0

@asveikau:違いは見えないのですか?バッファを提供するfgetsを使用するときは、任意のサイズに設定できます。そして、strings.txtの行がバッファよりも長い場合、私たちは問題になります...あなたはfgetsを使用していてもバッファオーバーフローのケースを管理すべきですか?確かにそうです。タイプのないバッファーよりもあまり明白ではありません。 – kriss

+0

fgets()は指定されたバッファ長まで読み込みます。空白がなくなるまでに改行が発生していなければ、それは停止して戻ります。したがって、最後の文字が改行でなく、バ​​ッファがいっぱいであれば、余分な文字を入れるためにさらにスペースを(再割り当て?)見つけることができ、fgets()をもう一度呼び出すことができます(注意深く - 余分なスペース)とより多くの行を取得します。だから、自分自身のリーダーを書くことで、動的に割り当てられたバッファにデータを取得させることができます。バッファを処理しているときにfgets()を使って読み込みを行うことができます。 –

2

ブロック単位で読むことは、基礎となるファイルシステムの仕組みによって常に優れています。

ブロック単位で読んだだけで、あなたの言葉がバッファに現れているかどうかを確認してください。 は、別のバッファがいっぱいになっています。検索語がバッファ境界にある場合、検出漏れを避けるために、新しいバッファ内の前のバッファの最後の数文字を再コピーするように注意するだけです。

この単純なアルゴリズムでは十分ではない場合(あなたの場合はおそらくそうです)、1つのバッファー内で複数の部分文字列を同時に検索するためのはるかに洗練されたアルゴリズムがありますcf Rabin-Karp

+0

fgetc()を使用すると、stdioはブロックとバッファ文字で読み込むことがかなり確実です... – asveikau

+0

trueですが、fgetcを呼び出すのはコストがかかり、文字列(または複数の文字列)どこかにコピーする必要があります。それは完全なバッファを読み、それを使って作業するよりはるかに大きなコストがかかります。 Jonathanが提案しているように、完全な行を読むことは、バッファを直接読み込むという細部の詳細を自分自身で管理したくない場合には、完全なバッファを読み取る良い選択肢です。 – kriss

2
cat strings.txt |while read x; do grep "$x" text_file.txt; done 
+1

あなたは 'fgrep -f strings.txt text_file.txt> out.txt'を意味しましたか? –

+0

はい、はい、 'fgrep -f strings.txt text_file.txt'です。私は、より多くの選択がより多くの選択肢を意味すると思います。 –

+0

ありがとうございます。これを行うためのCプログラムを書くことは、完全な時間の無駄です。 –