从具有未知格式的文本文件中读取

时间:2018-03-04 20:48:48

标签: c regex file-io dynamic-memory-allocation

我正在尝试从文本文件中读取。此文本文件没有特定的模式,但是故事的一个段落。我试图获取每个单词并跟踪它们的出现次数。

例如,这是文本文件的一个exerpt,用于说明格式。

  

在提交以下记录时,我们意识到我们有错误。其中一些已被发现和   即使在模板出来后,也用笔修正了。其他人,我认为你会找到。其他人不会   发现,今天我们中间没有一个人过去住了足够长的时间来了解他们。这是我们真诚的愿望   使这个记录尽可能准确。要做到这一点,我们必须得到你的帮助。如果你错了,请通知   这位作家将反过来纠正他的副本。我们打算重写这个故事,让它更具可读性   包括可用的个人利益故事;通过纠正你的错误更准确   可能会发现。前三页是直接拍摄的,没有任何由表亲写的家庭记录的变化   Ethel Mards Carr Marsh。我们非常感谢此信息。没有她的帮助,它本来就是   不可能超越丹尼尔和大卫的父母。如历史所述,四个沼泽兄弟   在1761年之前的某个时间来到殖民地。在这个日期之前多少年,我们不知道。塞缪尔马什,   Zebediah Marsh的儿子,出生于1761年。我们可以想象他出生前几年。我们有   研究了他们时期的英格兰记录。他们是危险的岁月。许多人来到美国是为了逃避愤怒   一个暴君沼泽王,其他人逃避清教徒克伦威尔的判断。

我知道如何从具有特定格式的文件中读取,但我不确定如何阅读此文件以查找没有标点符号的每个单词。

我猜我将使用带有正则表达式的fscanf来执行此操作,但我并不是100%确定如何实现此目的。

1 个答案:

答案 0 :(得分:1)

我说过你应该使用fgetsstrtok。你在评论中说过

  

如果我使用fgets进行设置,我不会超过缓冲区限制吗?另外,我最终可能只是半途而废了?

如果您使用的是POSIX系统,则可以使用此功能getline 将读取一行并正确分配空间以容纳整行。如果你 没有使用getline不可用的POSIX系统,你可以写一个 这样做的fgets包装。

我写过这样的包装并在过去使用过:

char *fgets_long(FILE *fp)
{
    size_t size = 0, currlen = 0;
    char line[1024];
    char *ret = NULL, *tmp;

    while(fgets(line, sizeof line, fp))
    {
        int wholeline = 0;
        size_t len = strlen(line);

        if(line[len - 1] == '\n')
        {
            line[len-- - 1] = 0;
            wholeline = 1;
        }

        if(currlen + len >= size)
        {
            // we need more space in the buffer
            size += (sizeof line) - (size ? 1 : 0);
            tmp = realloc(ret, size);
            if(tmp == NULL)
                break; // return all we've got so far
            ret = tmp;
        }

        memcpy(ret + currlen, line, len + 1);
        currlen += len;

        if(wholeline)
            break;
    }

    if(ret)
    {
        tmp = realloc(ret, currlen + 1);
        if(tmp)
            ret = tmp;
    }

    return ret;
}

这个函数也会给出整行并为内存分配内存 它

所以geline解决方案:

char *line = NULL;
size_t len = 0;

// commong word delimiters
const char *delim = " \t.,-!\r\n";

while(getline(&line, &len, fp) > 0)
{
    char *word = strtok(line, delim);

    if(line == NULL)
    {
        fprintf(stderr, "line has delimiters only, ignoring\n");
        continue;
    }

    do {
        do_your_calculations_with(word);
    } while((word = strtok(NULL, delim)));
}

free(line);

或包装器的解决方案

char *line;
// commong word delimiters
const char *delim = " \t.,-!\r\n";
while((line = fgets_long(fp)))
{
    char *word = strtok(line, delim);

    if(line == NULL)
    {
        fprintf(stderr, "line has delimiters only, ignoring\n");
        continue;
    }

    do {
        do_your_calculations_with(word);
    } while((word = strtok(NULL, delim)));

    free(line);
}