2012-03-23 4 views
1

내 함수는 열기 및 닫기 문자열 (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_
,451,515,_START_THIRD_END START 4 ​​END

"START"및 "END"가 포함되는 것으로 생각되지만, 세그먼트 3 ("START_THIRD_END")는 누락되고 2. 세그먼트 잘못에 "_"포함한다. 다른 입력 파일을 사용하면 결과가 부정확 해집니다. 아이디어가 있으십니까? 각 줄의 앞 4 자리를 추가 내가 여기 새로 왔어

#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; 
} 

은 수동으로 코드를 표시의 쉬운 방법은 무엇 총 악몽인가?

+0

모든 코드를 강조 표시하고 **'{}'** 버튼을 클릭하십시오. –

+1

나는 이것이 많이 요구된다는 것을 알고 있지만 들여 쓰기가 보존 된 상태에서 코드를 다시 작성한 다음'{} '을 수행하겠습니까? 읽을 시간이 조금 있습니다. 죄송합니다. – gbulmer

+0

파일의 크기는 얼마입니까? mmap() (Window $에서 MapViewOfFile)을 사용 해보십시오. –

답변

0

라인

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

약간 이상한. 하나의 테스트 또는 다른 테스트로 충분하지만 중요하지 않습니다.

나는 괜찮 으면 좋겠어.하지만 쓸 수있는 스타일로 프로그램을 구성하여 버그를 볼 수 있는지 확인하려고 노력했다. 그것은 나를 읽는데 도움이되었지만 새로운 버그는 보지 못했습니다. 단지 윌리엄 모리스의 것 :-(

필자는 '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

이 다른 문제 일 수 있지만, 하나의 확인 오류가 호출입니다 수 있습니다 포인터로 정의된다을 segment_filename_numbered하지만 수 세그먼트의 캐릭터 라인 표현을 저장하기에 충분히 큰 버퍼를 할 필요가

segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10); 

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

내가 전에 ltoa 건너 적이 없다. 정상적으로 snprintf를 사용하면 오버플로를 피하기 위해 버퍼 크기를 명시 할 수 있습니다.

편집하는 것은 나쁜 뜻은 의미가 없다, 그러나 당신은이 프로그램을 디버깅하려고 죽은 말을 채찍질하는

. 내 제안은 표준 라이브러리 문자열 함수 (strstr, strchr 등)를 조사하고 프로그램을 다시 작성하여 한 번에 하나 이상의 char을 읽는 것입니다. 프로그램에 응용 프로그램이 있습니까? 다른 말로하면 누군가가/어딘가에서 사용할 수 있습니까? 아니면 운동입니까?

+0

다른 방법으로 'segment_filename_numbered'는 char 포인터이지만, 아무 공간도 가리 키도록 초기화되지 않았으므로, ltoa가 사용하는 임의의 쓰레기를 가리키고 있습니다. – gbulmer

+0

잘 내 chars_cat2 (주석 처리 된) 함수는 메모리를 올바르게 할당합니다.이 줄은 모든 사람들이 컴파일 할 수 있도록하기 위해서입니다. 하지만 여전히 잘 알고 있으며 어쨌든 snprintf()를 살펴볼 것입니다. – user1287246

+0

@ 윌리엄 그 성능 문제를 볼, 그것은 큰 파일에 사용 될 것입니다, 지금은 충분히 빨리 (그 자주 사용하지 않을 것입니다) - 나는 그것을 최적화 신경 안 쓸데요, 그것은 복잡해질 것 같아요. 어쨌든 고맙습니다. – user1287246

1

좋습니다, 이번엔 생각합니다. "FREAD (세그먼트 size_segment 1 파일)"때문에 줄 필요하지 않은

fseek(file, size_segment, SEEK_CUR); 

: 문제는이 라인 이미 size_segment 바이트의 파일 위치를 이미 이동했습니다. 거기서 사실 fseek를 두 배로 늘 렸습니다. 그래서 문자를 건너 뛰는 것입니다 (각 루프 실행시 chr의 값을 인쇄 해보십시오. 문자는 건너 뜁니다)

+0

잘 했어! Funny - 너무 혼란 스러웠다. 나는 fseek (file, 0, SEEK_CUR) 파일 포인터가있는 곳을 찾고 싶었다. :-) – gbulmer