C-файл для нескольких групп символов * по разделителю слов - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть файл с содержимым, аналогичным приведенному ниже:

Really my data is here, and I think its really 
cool. Somewhere, i want to break on some really
awesome data. Please let me really explain what is going
'\n'
on. You are amazing. Something is really awesome. 
Please give me the stuffs. 

Я хотел бы создать массив строковых указателей на строки между словами-разделителями.

char **Строки:

my data is here, and I think its
cool. Somewhere, i want to break on some
awesome data. Please let me
explain what is going'\n'on. You are amazing. Something is
awesome.'\n'Please give me the stuffs.

Попытка кода:

char *filedata = malloc(fileLength);
fread(filedata, end, 1, fp); //ABC
size_t stringCount = 8;
size_t idx = 0;
char **data = malloc(stringCount * sizeof(*packets));
if(!data) {
    fprintf(stderr, "There was an error");
    return 1;
}
fread(data, end, 1, text);
char *stuff = strtok(data, "really");
while(stuff) {
    data[idx++] = strdup(stuff);
    s = strtok(NULL, "stuff");
    if(idx >= stringCount) {
        stringCount *= 2;
        void *tmp = realloc(stuff, stringCount * sizeof(*stuff));
        if(!tmp) {
            perror("Unable to make a larger string list");
            stringCount /= 2;
            break;
        }
        stuff = tmp;
    }
}

Это обеспечивает некоторую часть того, что я ищу, но не ограничивает само слово, а не буквы.

1 Ответ

0 голосов
/ 27 ноября 2018

У вас есть несколько тонких трудностей в том, чтобы пометить "файл" на слове "really".Кто они такие?Текстовые файлы, как правило, читаются по одной строке за раз и, если хранится и весь файл строк, как количество указателей, каждый из которых указывает на начало строки.Это означает, что если для чтения файла используется общий строчно-ориентированный подход, то ваши токены (начинающиеся в начале файла или со слова "really") могут занимать несколько строк.Таким образом, для токенизации вам нужно объединить несколько строк.

В качестве альтернативы, вы можете прочитать весь файл в один буфер и затем использовать strstr для анализа вашего разделителя "really", но... , вам нужно убедиться, что буфер, содержащий файл, завершен нулем , чтобы избежать неопределенного поведения последнего вызова strstr.(обычно чтение всего файла в буфер не приводит к созданию буфера с нулевым символом )

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

Схема довольно проста, ваш первый токен начинается и с начала файла, а каждый последующий токен начинается со слова "really".Вы сканируете вперед, чтобы найти " really" (обратите внимание на пробел перед " really"), установите указатель конца на начало вашего токена " really", скопируйте токен в буфер, /* do stuff with token */, free (token);, обновите началонаведите указатель на начало "really", установите общий указатель синтаксического анализа на единицу за "really" и повторяйте до тех пор, пока "really" не будет найден. Когда вы выходите из цикла синтаксического анализа, вам все равно придется /* do stuff */ с последним токеном.

Вы также можете решить, что делать с '\n', содержащимся в каждом токене. Для целей вывода, приведенных ниже, они просто перезаписываются с помощью ' ',(вы можете добавить любые дополнительные критерии, которые вам нравятся, такие как устранение любого пробела или промежуточного пробела, вызванного заменой новой строки, оставленной вам)

В целом, вы можете сделать что-то похожее на следующее, где чтениесодержимого файла в буфер nul-terminated обрабатывается функцией read_file(), а остальная часть токенизации просто обрабатывается в main(), например,

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

char *read_file (char* fname, size_t *nbytes)
{
    long bytes = 0;
    char* file_content;
    FILE *file = fopen(fname, "rb");

    if (!file)          /* validate file open for reading */
        return NULL;

    fseek (file, 0, SEEK_END);              /* fseek end of file */
    if ((bytes = ftell (file)) == -1) {     /* get number of bytes */
        fprintf (stderr, "error: unable to determine file length.\n");
        return NULL;
    }

    fseek (file, 0, SEEK_SET);              /* fseek beginning of file */

    /* allocate memory for file */
    if (!(file_content = malloc (bytes + 1))) { /* allocate/validate memory */
        perror ("malloc - virtual memory exhausted");
        return NULL;
    }

    /* read all data into file in single call to fread */
    if (fread (file_content, 1, (size_t)bytes, file) != (size_t)bytes) {
        fprintf (stderr, "error: failed to read %ld-bytes from '%s'.\n",
                bytes, fname);
        return NULL;
    }
    fclose (file);              /* close file */

    file_content[bytes] = 0;    /* nul terminate - to allow strstr use */

    *nbytes = (size_t)bytes;    /* update nbytes making size avialable */

    return file_content;        /* return pointer to caller */
}

int main (int argc, char **argv) {

    size_t nbytes;
    char *content;

    if (argc < 2) {     /* validate required argument givent */
        fprintf (stderr, "error: insufficient input. filename req'd.\n");
        return 1;
    }

    if ((content = read_file (argv[1], &nbytes))) { /* read/validate */
        char *sp = content,     /* start pointer for token */
            *p = sp,            /* pointer for parsing token */
            *ep = p;            /* end pointer one past end of token */
        const char *delim = " really";      /* delimiter */

        while ((ep = strstr (p, delim))) {  /* while delimiter found */
            if (isspace (*(ep + sizeof delim - 1)) ||   /* if next isspace */
                ispunct (*(ep + sizeof delim - 1))) {   /* or next ispunct */
                /* delimiter found */
                size_t tlen = ep - sp;              /* get token length */
                char *token = malloc (tlen + 1),    /* allocate for token */
                    *tp = token;                    /* pointer to token */
                if (!token) {                       /* validate allocation */
                    perror ("malloc-token");
                    exit (EXIT_FAILURE);
                }
                memcpy (token, sp, tlen);           /* copy to token */
                *(token + tlen) = 0;                /* nul-termiante */
                while (*tp) {               /* replace '\n' with ' ' */
                    if (*tp == '\n')
                        *tp = ' ';
                    tp++;
                }
                printf ("\ntoken: %s\n", token);    /* output token */
                /* do stuff with token */
                free (token);                       /* free token memory */
                sp = ep + 1;    /* advance start to beginning of next token */
            }
            p = ep + sizeof delim;  /* advance pointer */
        }
        p = sp;             /* use p to change '\n' to ' ' in last token */
        while (*p) {        /* replacement loop */
            if (*p == '\n')
                *p = ' ';
            p++;
        }
        printf ("\ntoken: %s\n", sp);
        /* do stuff with last token */

        free (content);     /* free buffer holding file */
    }

    return 0;
}

Пример входного файла

$ cat dat/breakreally.txt
my data is here, and I think its really
cool. Somewhere, i want to break on some really
awesome data. Please let me really explain what is going
on. You are amazing.

Пример использования / вывода

$ ./bin/freadbreakreally dat/breakreally.txt

token: my data is here, and I think its

token: really  cool. Somewhere, i want to break on some

token: really awesome data. Please let me

token: really explain what is going on. You are amazing.

Просмотрите все и дайте мне знать, если у вас есть какие-либо вопросы.

...