【问题标题】:Parsing a comma separated file using C using fscanf()使用 C 使用 fscanf() 解析逗号分隔的文件
【发布时间】:2014-01-28 15:56:38
【问题描述】:

我有一个包含类似数据的文件 -

Name, Age, Occupation
John, 14, Student
George, 14, Student
William, 23, Programmer

现在,我想读取数据,以便将每个值(例如姓名、年龄等)读取为字符串。
这是我的代码 sn-p -

....
if (!(ferror(input_fp) || ferror(output_fp))) {
    while(fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]", 
                name, age_array, occupation) != EOF){
        fprintf(stdout, "%-30s%-30s%-30s\n", name, age_array, occupation);
    }
    fclose(input_fp);
    fclose(output_fp);
}
....

但是,这会进入一个无限循环,并给出一些随机输出。
这就是我对input conversion specifiers 的理解。
%30[^ ,\n\t] -> 读取的字符串长度最多为 30 个字符,并且
DOES NOT 包含空格、逗号、换行符或制表符。
我正在阅读 3 个这样的字符串。
我哪里错了?

【问题讨论】:

  • while(fscanf(stdin, " %30[^ ,\n\t], %30[^ ,\n\t], %30[^ ,\n\t]", name, age_array, occupation) == 3){

标签: c file-io scanf


【解决方案1】:

OP的

fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]", ...

不使用文本文件中的',' 和'\n'。随后的fscanf() 尝试也失败并返回值 0,这不是EOF,导致无限循环。


虽然 OP 请求了 fscanf() 解决方案,但 fgets()/sscanf() 更好地处理潜在的 IO 和解析错误。

FILE *input_fp;
FILE *output_fp;
char buf[100];
while (fgets(buf, sizeof buf, input_fp) != NULL) {
  char name[30];  // Insure this size is 1 more than the width in scanf format.
  char age_array[30];
  char occupation[30];
  #define VFMT " %29[^ ,\n\t]"
  int n;  // Use to check for trailing junk

  if (3 == sscanf(buf, VFMT "," VFMT "," VFMT " %n", name, age_array,
      occupation, &n) && buf[n] == '\0') {
    // Suspect OP really wants this width to be 1 more
    if (fprintf(output_fp, "%-30s%-30s%-30s\n", name, age_array, occupation) < 0)
      break;
  } else
    break;  // format error
}
fclose(input_fp);
fclose(output_fp);

不要调用ferror(),而是检查fgets()、fprintf()的返回值。

可疑 OP 的未声明字段缓冲区为 [30],并相应调整了 scanf()。


[编辑]

关于if (3 == sscanf(buf, VFMT "," ...的详细信息

if (3 == sscanf(...) &amp;&amp; buf[n] == '\0') { 在以下情况下变为真:
1) 至少 1 个 char 中的每个 scanf 中的 3 个 "%29[^ ,\n\t]" 格式说明符。
2) buf[n] 是字符串的结尾。 n 是通过 "%n" 说明符设置的。 " %n" 中的前面 ' ' 会导致使用最后一个 "%29[^ ,\n\t]" 之后的任何后续空格。 scanf() 看到"%n",这指示它设置从扫描开始的当前偏移量,以分配给&amp;n 指向的int。

"VFMT "," VFMT "," VFMT " %n" 被编译器连接到
" %29[^ ,\n\t], %29[^ ,\n\t], %29[^ ,\n\t] %n"。
我发现前者比后者更容易维护。

" %29[^ ,\n\t]" 中的第一个空格指示sscanf() 扫描(使用而不是保存)0 个或多个空格(' '、'\t'、'\n' 等)。其余指示 sscanf() 消耗和保存 any 1 到 29 char except ','、'\n'、'\t',然后附加一个 '\0' .

【讨论】:

  • 你能解释一下这个说法吗 - (3 == sscanf(buf, VFMT "," VFMT "," VFMT " %n", name, age_array, occupation, &amp;n) &amp;&amp; buf[n] == '\0')。还有,为什么" %29[^ ,\n\t]"里面有一个空格。我也无法获得最后一列。
  • @Vishal Yadav 查看编辑。该空间占用了"," 和"Age" 之间的空间。 “最后一列”问题很可能是"%-30s%-30s%-30\n" 中缺少s,现已更正。
【解决方案2】:

您不会跳过值之间的实际逗号和空格。

一旦第一个 %30[^ ,\n\t] 说明符匹配,输入可能包含逗号和空格,格式字符串中的以下内容不匹配。

在输入中预期的格式字符串中添加逗号和空格:

while(fscanf(input_fp, "%30[^ ,\n\t], %30[^ ,\n\t], %30[^ ,\n\t]", name, age_array, occupation) == 3)
                                    ^             ^
                                    |             |
                                    \             /
                                   add these to make
                                   fscanf() skip them
                                      in the input!

此外,您对fscanf() 的返回值的检查不是最佳的:在依赖已转换的值之前,您应该检查返回值是否等于转换次数。

另外,您对反斜杠续行字符的使用完全没有意义,应该删除。

【讨论】:

  • 你能具体解释一下吗?
  • 我得到了第一个字符串可能包含“,”的部分,但是如何跳过“非必要字符”?你能解释一下 fscanf() 的返回值部分吗?在我经历的许多示例中,这就是检查文件结尾的方式。 (“非必要字符”是指任何空格或逗号)
  • 第一行输入完成后第二行输入失败。
  • 需要在某处消耗最终的'\n'。也许在前 30 个 " %30[^ ,\n\t]... 或 ...\n\t]%*c" 之前有空格。
猜你喜欢
  • 2013-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多