2012-03-23 53 views
1

我的函數使用開始和結束字符串(請參閱main()) 解析文本文件 中的段,並將段保存在單獨的文件中。C I/O和字符串解析 - 行爲不規律

我不知道什麼是錯的,但它返回這3段文件:

1 START_TEXT_END
2 _START_BLABLUB_END
3 START 4 END

此輸入的test.txt (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

突出顯示所有代碼並單擊**'{}'**按鈕。 – 2012-03-23 01:21:47

+1

我意識到這是相當多的要求,但會重新保存你的代碼,並保留縮進,然後執行'{}'?這是有點難以閱讀。抱歉。 – gbulmer 2012-03-23 01:38:02

+0

文件有多大?嘗試使用mmap()(Window $中的MapViewOfFile) – 2012-03-23 11:43:49

回答

0

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

有點奇怪。一個或另一個測試就足夠了,但沒關係。

我希望你不要介意,但我試圖按照我可能寫的風格來組織程序,看看我能否看到一個bug。它幫助我閱讀,但我沒有看到任何新的錯誤,只有威廉莫里斯的:-(

我想我可能會試圖'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 2012-03-23 01:56:32

0

我覺得你的問題是在你尋求回來,隔板之間獲取數據:

FSEEK(文件,-size_segment,SEEK_CUR);

問題是你回去「size_segment」字節,但你已經閱讀更多:size_segment + size_str_end(段結尾)。 你應該寫:

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

現在,它似乎並不十分有效的處理數據,這種方式(讀取數據,發現結局,尋求回的數據,寫入文件,然後尋找到以前的位置)。 爲什麼不在輸出文件中讀取數據時立即寫入數據,並在遇到結束文本時更改輸出文件?

如果您首先搜索循環中的開始文本,然後是數據(您寫入文件),同時期待結束文本,它會更乾淨。在這裏,你同時擁有了所有的東西,這很難遵循。

+0

該功能實際上應該存儲包括分隔符在內的段......但是,當然我會在閱讀開始分隔符後立即寫入段文件!我怎麼會錯過 - 無論如何應該解決它, – user1287246 2012-03-23 02:24:48

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,它允許您指定緩衝區大小以避免溢出。

編輯

沒有冒犯的意思,但你白費力氣試圖調試此程序。我的建議是,您調查標準庫字符串函數(strstr,strchr等)並重寫程序,一次讀取多個字符。該程序是否有應用程序 - 換句話說,它是在某個地方/某人使用 - 還是一個練習?

+0

換言之,'segment_filename_numbered'是一個字符指針,但它沒有被初始化爲指向任何空間,所以它指向隨機垃圾,這是ltoa使用的。 – gbulmer 2012-03-23 02:23:54

+0

以及我的chars_cat2(註釋掉因爲)函數正確分配內存 - 該行只是讓每個人都可以編譯它。但它仍然是很好的知道,我會看看snprintf()的東西。 – user1287246 2012-03-23 02:31:43

+0

@William我看到性能問題,它將用於大文件,它現在起作用,它的速度足夠快(它不會被經常使用) - 我想我不會優化它,它會變得複雜。無論如何謝謝您 – user1287246 2012-03-23 03:19:27

1

好的,這次我想到了。 的問題是此行:不需要

fseek(file, size_segment, SEEK_CUR); 

它,這是因爲線 「的fread(段,size_segment,1,文件);」已經將size_segment字節的文件位置提前移動了。事實上,你有兩倍fseek。這就是爲什麼你跳字符(嘗試在每次循環運行時打印字符串的值,它跳過字符)

+0

幹得好!有趣 - 我很困惑,我覺得我想fseek(文件,0,SEEK_CUR)只是爲了找到文件指針的位置:-) – gbulmer 2012-03-23 03:39:22