使用fscanf()使用C解析逗号分隔文件

yad*_*_vi 4 c file-io scanf

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

Name, Age, Occupation
John, 14, Student
George, 14, Student
William, 23, Programmer
Run Code Online (Sandbox Code Playgroud)

现在,我想读取数据,使每个值(例如Name,Age等)作为字符串读取.
这是我的代码片段 -

....
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);
}
....
Run Code Online (Sandbox Code Playgroud)

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

chu*_*ica 7

OP的

fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]", ...
Run Code Online (Sandbox Code Playgroud)

不消耗文本文件中的','也不是'\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);
Run Code Online (Sandbox Code Playgroud)

而不是打电话ferror(),检查fgets(),fprintf().的返回值.

怀疑OP的未申报的现场缓冲区已相应[30]调整scanf().


[编辑]

详情 if (3 == sscanf(buf, VFMT "," ...

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

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

在第一空间" %29[^ ,\n\t]"定向sscanf()扫描整个(消耗和不保存)0以上的空格(' ','\t','\n'等等).其余指示sscanf()要消耗并保存任何 1至29 char ',','\n','\t',然后追加一个'\0'.