【问题标题】:C - Ignore trailing comments when reading text fileC - 阅读文本文件时忽略尾随注释
【发布时间】:2014-09-20 20:17:26
【问题描述】:

我有一个格式如下的文本文件:

1 // Comment
2 // Comment
3 
4 // Comment
5
6 // Comment
7 // Comment
8 // Comment
9 
etc.....

我正在使用 C 尝试解析数字,同时完全忽略 cmets,并将整数读入数组。该数组具有预定大小,因此文本文件中的数字数量不会超过该大小。我刚开始学习 C,我尝试过将 fgets() 和 strtok() 与以下程序一起使用:

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

int main(int argc, char *argv[])
{
    FILE *file;
    char buf[1000];

    if (argc == 2)
        file = fopen(argv[1], "r");
    else {
        fprintf(stderr, "Incorrect number of arguments.\n");
        return 1;
    }

    if (!file)
        return 1;

    while (fgets(buf, sizeof(buf), file) != NULL)

        printf("%s\n", strtok(buf, "//"));


    fclose(file);
    return 0;
}

我还没有尝试将整数放入数组中,因为我仍在尝试以某种方式隔离数字。这是我的输出:

1 
2 
3 

4 
5

6 
7 
8 
9

所以,我在处理数字后面的空白时遇到了麻烦。据我所知,可能有一种更简单的方法可以实现这一点,但这是我在搞砸了几个小时后得到的。我该如何解释这个空间,或者,有没有更好的方法来只解析这个文件中的整数并放入一个数组中?

【问题讨论】:

  • 格式是否总是“数字[空格][可选注释]”?
  • 您是否阅读过strtok(3) 的文档;你使用不正确!此外,使用所有警告和调试信息 (gcc -Wall -g) 进行编译并使用调试器 (gdb)
  • @templatetypedef 是的,格式总是数字[空格][可选注释]
  • 格式到底是什么?是:digits [non-digit-non-newline non-newlines] newline 吗?那个空间也是可选的吗?
  • @Deduplicator 首先是一个数字,后跟 3 到 4 个空格,具体取决于它是一位数还是两位数。然后是一个可选的注释,在注释之后的一个空格和不同长度的注释本身

标签: c parsing


【解决方案1】:

fgets() 将换行符 (\n) 留在行上(如果存在)。所以带有 cmets 的行是: ## // 评论\n 没有 cmets 的行是: ##\n

当您调用 strtok() 时,它会根据分隔符将行拆分为标记,在您的情况下为“//”。因此,带有 cmets 的行返回“##”和“Comment\n”,而没有 cmets 的行只返回“##\n”。因此,当您打印它们时,没有 cmets 的行以两个换行结束。

以这种格式检索您的号码的一种简单方法是 atoi(buf)。由于 atoi() 会跳过前导空格,解析选项前导 + 或 - 号,然后解析所有数字,因此在有注释行和没有注释行的情况下,它将返回数字的整数值。

【讨论】:

  • 我之前没有注意到我的 .txt 文件的这一点,但是有些行只是空白,并且在使用 aoti() 时,这些空白行被读入为零。我无法将有效的 0 放入我的数组并忽略空行(不将它们作为 0 读入数组)。
  • 好吧,我想出了如何通过检查“\n”来忽略空白行,但现在我正在尝试处理间隔超过 6 个空格左右的 cmets(“//”类型) .
  • 我的理解是第一个文件是你的输入,没有空行,第二个文件是你使用strtok()尝试获取数字后的输出。我的建议是不要使用 strtok(),而是使用 atoi()。如果您在该文件中有空行,那么您确实需要检查 buf[0] == '\n'
  • 我已经使用 buf[0] == '\n' 计算了空白行,但也有一些注释行不跟踪整数。例如,有一个类似于上面发布的输入的行块,然后是一个空白行,然后是一个开头没有整数的注释行,间隔大约 6 个空格(没有制表符)。所以'//'在几个空格标记之后开始。我无法解释这一点,并且 atoi() 继续将此注释行读取为零。
  • atoi() 将返回 0,除非它找到数字。现在,您说您的输入行是:“没有空格、数字、空格和注释”、“没有空格和数字”和“空格和 cmets”,对吧?这是输入文件中的所有行格式吗?你只应该计算有数字的行吗?如果所有 3 个问题的答案都是正确的,则添加 'if( !isdigit(buf[0]) { continue }' 以跳过开头没有数字的行,然后调用 atoi(buf) 并添加结果到您的列表中。
【解决方案2】:

由于每一行都以数字开头,并且该行的其余部分应被忽略,因此请执行以下操作:

int number;
while(1 == fscanf(file, "%d%*[^\n]\n", &number)) {
    // Work with number here
}

格式为:

  • %d:一个有符号的十进制数适合int
  • %*[^\n]:由于*,非换行符的字符数不受限制,不会被分配
  • \n:换行符终止行

fscanf 返回分配的输出数量,如果无法匹配将停止。

【讨论】:

  • 请注意,"%d%*[^\n]\n" 不会直接在数字后面使用 '\n'。下一次调用fscanf() 将消耗它。所以这种格式可以变成"%d%*[^\n]" 并执行相同的操作。
猜你喜欢
  • 2022-06-29
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多