2012-03-23 18 views
1

My関数は、テキストファイル のセグメントを解析し、開始文字と終了文字列(main()を参照) を使用してセグメントを別々のファイルに保存します。C I/Oと文字列解析が正しく動作しません

私はそれと間違っているかわからないが、それはこれらの3つのセグメントファイルを返します。この入力test.txtのため

1 START_TEXT_END
2 _START_BLABLUB_END
3 START 4 END

を(4 START ... ENDセグメント):

_START_TEXT_END_START_BLABLUB_END_
_START_THIRD_END START 4 END

"START" と "END" が含まれることになっているが、セグメント3( "START_THIRD_END")は および2セグメントが欠落している誤って "_" を含みます。他の入力ファイルでは、結果が不正確になります。

#include "stdio.h" 
#include "string.h" 
#include "stdlib.h" 

long split(char *filename, char *segment_filename, char *str_start, char *str_end, long n_start, long n_end) { 
    long segments = 0, size_segment = 0; 
    FILE *file = fopen(filename, "rb"), *segmentfile; 
    long size_str_start = strlen(str_start); 
    long size_str_end = strlen(str_end); 
    long pos_str_start = 0; 
    long pos_str_end = 0; 
    int chr; 
    char *segment_filename_numbered; 
    char *segment = (char*)malloc(1); 
    fseek(file,0,0); 

    if (file) { 
     while ((chr = fgetc(file)) != EOF && !feof(file) && !ferror(file)) { 
      size_segment++; 

      // scan for start string 
      if (chr == str_start[pos_str_start]) { pos_str_start++; } 
      else pos_str_start = 0; 
      if (pos_str_start == size_str_start) 
      size_segment = size_str_start, pos_str_start = 0; 

      // scan for end string 
      if (chr == str_end[pos_str_end]) pos_str_end++; 
      else pos_str_end = 0; 

      if (pos_str_end == size_str_end) 
      { 
       pos_str_end = 0; 
       segments++; 
       if (segments > n_start) { 
        segment = (char*) realloc(segment, size_segment); 
        //segment_filename_numbered = chars_cat2(segment_filename, chars_number(segments,  '0', 8, 16)); // SOME OF MY LIBRARY FUNCTIONS 
        segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10); 
        fseek(file, -size_segment, SEEK_CUR); 
        fread(segment, size_segment, 1, file); 
        segmentfile = fopen(segment_filename_numbered, "wb"); 
        fwrite(segment, size_segment, 1, segmentfile); 
        fseek(file, size_segment, SEEK_CUR); 
        fclose(segmentfile); 
       } 
      } 
     } 

     fclose(file); 
    } 

    return segments; 
} 


int main(int argc, char* argv[]) 
{ 
    split("test.txt", "test_", "START", "END", 0, 0); 
    system("Pause"); 
    return 0; 
} 

私はここに新たなんだ、手動で各ラインの前に4つのスペースを追加すると、合計悪夢で、コードをマーキングする簡単な方法は何ですか?

+0

すべてのコードを強調表示し、** '{}' **ボタンをクリックします。 –

+1

これは非常にたくさんありますが、インデントが保存された状態でコードを再ペーストしてから、 '{}'を実行することを認識していますか?読むのが少し難しいです。ごめんなさい。 – gbulmer

+0

ファイルの大きさはどれくらいですか? mmap()を使用してみてください。(Window $のMapViewOfFile) –

答えて

0

ライン

while ((chr = fgetc(file)) != EOF && !feof(file) ... 

少し奇妙です。 1つのテストか他のテストで十分ですが、問題はありません。

私はあなたが気に入らないことを願っていますが、私が書くかもしれないスタイルに沿ってプログラムを整理しようとしました。それは私がそれを読むのに役立ったが、私は新しいバグは見なかった。ウィリアム・モリスだけが---(

私は「fseek 0」を使ってファイルの開始位置と終了位置を知りたいと思うかもしれないそれは効率的ではありません。少なくともそれをデバッグするのに役立つかもしれません - )

他の人がそれに従うのを助けるかもしれません。私が間違いを犯した場合、それは明らかではない領域かもしれません。

#include "stdio.h" 
#include "string.h" 
#include "stdlib.h" 

long split(char *filename, char *segment_filename, 
      char *str_start, char *str_end, 
      long n_start, long n_end) { 
    long segments = 0, size_segment = 0; 
    FILE *file, *segmentfile; 
    long size_str_start = strlen(str_start); 
    long size_str_end = strlen(str_end); 
    long pos_str_start = 0; 
    long pos_str_end = 0; 
    int chr; 
    char *segment_filename_numbered; 
    char *segment = (char*)malloc(1); 
    // fseek(file,0,0); 
    enum {LOOKING_FOR_START, LOOKING_FOR_END, MATCHED_MARKERS } 
     state = LOOKING_FOR_START; 

    if ((file=fopen(filename, "rb")) == NULL) { 
     fprintf(stderr, "Error: can't open file %s\n", filename); 
     return 0; 
    } 

    while ((chr = fgetc(file)) != EOF && !feof(file) && !ferror(file)) { 
     size_segment++; 

     switch (state) { 
      case LOOKING_FOR_START: 
       // scan for start string 
       if (chr == str_start[pos_str_start]) { pos_str_start++; } 
       else pos_str_start = 0; 
       if (pos_str_start == size_str_start) { 
        size_segment = size_str_start; 
        pos_str_start = 0; 
        state = LOOKING_FOR_END; 
       } 
       break; 
      case LOOKING_FOR_END: 
       // scan for end string 
       if (chr == str_end[pos_str_end]) pos_str_end++; 
       else pos_str_end = 0; 
       if (pos_str_end == size_str_end) 
       { 
        pos_str_end = 0; 
        state = MATCHED_MARKERS; 
       } 
       break; 
      case MATCHED_MARKERS: 
       segments++; 
       if (segments > n_start) { 
        segment = (char*) realloc(segment, size_segment); 
        //segment_filename_numbered = chars_cat2(segment_filename, chars_number(segments,  '0', 8, 16)); // SOME OF MY LIBRARY FUNCTIONS 
        //*** Error: uninitialised segment_filename_numbered *** 
        segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10); 
        fseek(file, -size_segment, SEEK_CUR); 
        fread(segment, size_segment, 1, file); 
        segmentfile = fopen(segment_filename_numbered, "wb"); 
        fwrite(segment, size_segment, 1, segmentfile); 
        fseek(file, size_segment, SEEK_CUR); 
        fclose(segmentfile); 
       } 
       state = LOOKING_FOR_START; 
      default: 
       fprintf(stderr, "Fatal Error: state has become corrupt, value is %d\n", state); 
       break; 
     } 
    } 

    fclose(file); 

    return segments; 

} 


int main(int argc, char* argv[]) 
{ 
    split("test.txt", "test_", "START", "END", 0, 0); 
    system("Pause"); 
    return 0; 
} 
+0

@ user1287246 - お詫び申し上げます。 – gbulmer

0

私はあなたの問題はあなたの、背中求めるセパレータとの間でデータをフェッチすることであると思う:

fseek関数(ファイル、-size_segment、SEEK_CUR);

問題は "size_segment"バイトに戻ってきましたが、さらに読むことがあります:size_segment + size_str_end(セグメントの終了)。 あなたが書く必要があります:

fseek(file, -size_segment - size_str_end,SEEK_CUR); 

を今、前の位置に、次に求め、ファイルに書き込め、データバックに求め、エンディングを見つけ、データを読み込む(データを処理するためにこの方法を非常に効率的ないないようです)。 出力ファイルでデータを読み込むとすぐにデータを書き出し、終了テキストに遭遇したときに出力ファイルを変更するのはなぜですか?

ループ内の開始テキストを最初に検索した後、終了テキストを期待してデータ(ファイルに書き込む)を最初に検索すると、よりクリーンになります。ここでは、すべてが同時に得られているので、それは難しいです。

+0

実際には区切り文字を含む区画を格納することになっています...しかし、もちろん、区切り記号を読んだ直後に区画ファイルを書きます!どのように私はそれを解決する必要があります - とにかくそれを解決する必要があります、 – user1287246

1

他の問題があるかもしれませんが、1つの確認してくださいエラーが呼び出しです:

segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10); 

をsegment_filename_numberedポインタとして定義されているが数セグメントの文字列表現を保持するのに十分な大きさのバッファする必要があります

char segment_filename_numbered[16]; 
ltoa(segments, segment_filename_numbered, 10); 

私は以前にltoaを訪れていません。私は通常snprintfを使用します。これによりオーバーフローを避けるためにバッファサイズを指定することができます。

EDIT

悪気は意味しますが、このプログラムをデバッグしようとして死んだ馬を鞭打ちされています。私の提案は、標準のライブラリ文字列関数(strstr、strchrなど)を調べて、一度に複数の文字を読み取ってプログラムを書き直すことです。プログラムにはアプリケーションがありますか?言い換えればどこか/誰かによって使用されることですか?それとも運動ですか?

+0

別の言い方をすれば、 'segment_filename_numbered'はcharポインタですが、それはltoaが使うランダムなゴミを指しています。 – gbulmer

+0

私のchars_cat2(コメントアウトされたため)関数はメモリを正しく割り当てます。その行はすべての人がコンパイルできるだけのものです。でもそれはまだ分かっていて、とにかくそのsnprintf()を見ていきます。 – user1287246

+0

@ウィリアム私はそのパフォーマンスの問題を参照してください、それは大きなファイルに使用される、それは今すぐ、十分に速く(非常に頻繁に使用されることはない) - 私はそれを最適化するつもりはないと思う、複雑になるだろうと思う。とにかくありがとうございます。 – user1287246

1

これはいいと思います。 問題は、この行です:

fseek(file, size_segment, SEEK_CUR); 

ラインので、それは、必要とされていない "のfread(セグメント、size_segment、1、ファイル);"すでにsize_segmentバイトのファイル位置を先に移動しました。あなたは実際にfseekを倍増させました。だからこそ、あなたは文字をスキップしています(各ループ実行時にchrの値を表示しようとすると文字はスキップされます)

+0

よくできました!面白い - 私はとても混乱していました。私はfseek(file、0、SEEK_CUR)にファイルポインタがどこにあるかを知りたいと感じました:-) – gbulmer