在C语言中按行和字解析文件

hwamh0ep  于 2023-04-29  发布在  其他
关注(0)|答案(2)|浏览(99)

我正在用C语言做一个中等项目,在某个部分我需要一个函数来获取FILE*参数,文件有严格的规则(数据表),我需要逐行解析和存储数据,每行我需要逐词解析并使用这些单词。
问题是,对于每一行,我需要根据该行中的字数分配内存,我尝试使用fgetsstrtok" " delim,当只使用一次时,它工作,但是strtok在我做两次的时候就坏了(尝试先计数单词,然后分配内存,最后再次解析单词并存储数据)。
有没有更好的方法来实现这个功能?如果没有,我如何修复strtok的bug?
数据文件示例:

123456789
234123 234567 239875 789406 89044
132456789 98372816

我需要扫描每一个int,但这一行很重要,第一行代表一些东西,第二行代表另一些东西。我对数据的唯一假设是:所有数字都不会以0开头。
第二个行号是最大MAX_INT。
第一行和第三行的数字是9位数字。
我不知道每行有多少数字

2lpgd968

2lpgd9681#

strtok()修改它将其分成单词的缓冲区,因此如果您希望对该行进行两次解析,则必须复制一个副本。
strtok返回的指针指向输入行,因此您必须进行复制以存储到所分配的指针数组中。使用strdup()
要将行拆分为空格分隔的单词,您应该使用" \t\n"作为分隔符列表,否则fgets()存储的尾随换行符将成为每行最后一个单词的一部分。
下面是一个使用链接列表的替代方法:

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

#define MAX_LINE_LENGTH 500

struct Word {
    char *word;
    struct Word *next;
};

struct Line {
    struct Word *head;
    struct Word *tail;
    struct Line *next;
};

struct Line *new_line(void) {
    struct Line *lp = calloc(1, sizeof(*lp));
    if (lp == NULL) {
        perror("cannot allocate line");
        exit(1);
    }
    lp->head = lp->tail = NULL;
    lp->next = NULL;
    return lp;
}

struct Word *new_word(struct Line *lp, const char *word) {
    struct Word *wp = calloc(1, sizeof(*wp));
    if (wp == NULL) {
        perror("cannot allocate word");
        exit(1);
    }
    wp->word = strdup(word);
    wp->next = NULL;
    if (lp->head == NULL) {
        return lp->head = lp->tail = wp;
    } else {
        return lp->tail = lp->tail->next = wp;
    }
}

int main(int argc, char *argv[]) {
    char line[MAX_LINE_LENGTH];
    struct Line *head = NULL;
    struct Line **tailp = &head;

    const char *filename = (argc > 1) ? argv[1] : "filename.txt";
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno));
        return 1;
    }

    while (fgets(line, sizeof line, fp) != NULL) {
        struct Line *lp = new_line();
        // link the line at the end
        *tailp = lp;
        tailp = &(*tailp)->next;
        char *word = strtok(line, " \t\n");
        while (word != NULL) {
            new_word(lp, word);
            word = strtok(NULL, " \t\n");
        }
    }

    fclose(fp);

    for (struct Line *lp = head; lp; lp = lp->next) {
        for (struct Word *wp = lp->head; wp; wp = wp->next) {
            printf("%s ", wp->word);
        }
        printf("\n");
    }
    return 0;
}
wxclj1h5

wxclj1h52#

首先,读取数组中的所有字符,然后基于“”对单词进行标记。我用过getc,你可以很容易地用fgetc来减少开销。
如果将整个文件读入字符数组,您不必担心单词会在中途被拆分,因为使用MAX_LENGTH可以在中途拆分单词。

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

int main() {

    FILE* file = fopen("filename.txt", "r"); // Open file for reading
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }

    int c; 
    int text_size = 4;
    char * text = malloc(sizeof(char)*text_size);
    int size = 0;

    while ((c = fgetc(file)) != EOF) { 

        if(size==text_size){
            text_size *= 2;
            text = realloc(text, text_size);
        }

        text[size++] = (char)c;

    }

    char * word = strtok(text, " ");
    while (word != NULL) {
        printf("%s\n", word);
        word = strtok(NULL, " ");
        }

    fclose(file);

    return 0;

}

相关问题