C I / O и синтаксический анализ строки - ведут себя хаотично - PullRequest
1 голос
/ 23 марта 2012

Моя функция разбирает сегменты из текстового файла используя открывающую и закрывающую строку (см. main ()) и сохраняет сегменты в отдельных файлах.

Я не знаю, что с ним не так, но он возвращает эти 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 пробелов перед каждой строкой вручную - это просто кошмар, какой простой способ пометить код?

Ответы [ 4 ]

1 голос
/ 23 марта 2012

ОК, я понял. Вопрос в этой строке:

fseek(file, size_segment, SEEK_CUR);

Это не нужно, потому что строка "fread (сегмент, размер_сегмент, 1, файл);" уже сдвинул позицию файла байтов size_segment вперед. Там вы удваиваете fseek на самом деле. Вот почему вы пропускаете символы (попробуйте печатать значение chr при каждом запуске цикла, это пропускает символы)

1 голос
/ 23 марта 2012

Могут быть и другие проблемы, но одной верной ошибкой является вызов:

segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10);

сегмент_файла_numbered определен как указатель, но должен быть достаточно большим буфером для хранения строкового представления числа сегментов

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

Я раньше не сталкивался с Итоа. Я бы обычно использовал snprintf, который позволяет вам указывать размер буфера, чтобы избежать переполнения.

EDIT

Не в обиду, но вы порете мертвую лошадь, пытаясь отладить эту программу. Я предлагаю вам изучить стандартные строковые функции библиотеки (strstr, strchr и т. Д.) И переписать программу, считывая более одного символа за раз. Есть ли в программе приложение - иными словами, оно будет использоваться где-то / кем-то - или это упражнение?

0 голосов
/ 23 марта 2012

Я думаю, что ваша проблема в поиске назад для получения данных между разделителями:

fseek (file, -size_segment, SEEK_CUR);

Проблема в том, что вы возвращаетесь "size_segmentmsgstr "байтов, но вы прочитали больше: size_segment + size_str_end (окончание сегмента).Вы должны написать:

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

Теперь, кажется, не очень эффективно обрабатывать данные таким образом (считывать данные, находить конец, искать данные, записывать в файл, искать затем предыдущийпозиция).Почему бы вам не записать данные, как только вы прочитаете их в выходном файле, и изменить выходной файл, когда вы встретите конечный текст?

И было бы лучше, если бы вы сначала искали начальный текст вцикл, затем данные (которые вы записываете в файл), ожидая окончания текста.Здесь у вас есть все одновременно, за ним трудно следить.

0 голосов
/ 23 марта 2012

Строка

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