【问题标题】:Reading values from CSV file into variables将 CSV 文件中的值读入变量
【发布时间】:2013-09-15 05:41:45
【问题描述】:

我正在尝试编写一段简单的代码来从 CSV 文件中读取值,其中最多 100 个条目到结构数组中。

CSV文件的一行示例:

1,Mr,James,Quigley,Director,200000,0

我使用以下代码读取值,但是当我打印出这些值时它们不正确

for(i = 0; i < 3; i++) /*just assuming number of entries here to demonstrate problem*/
    {
    fscanf(f, "%d,%s,%s,%s,%s,%d,%d", &inArray[i].ID, inArray[i].salutation, inArray[i].firstName, inArray[i].surName, inArray[i].position, &inArray[i].sal, &inArray[i].deleted);
    } 

然后当我打印出名字时,值都分配给了名字:

for(j = 0; j < 3; j++) /* test by printing values*/
    {
    printf("Employee name is %s\n", inArray[j].firstName);
    } 

以这种方式给出ames,Quigley,Director,200000,0 等等。我确定这是我格式化 fscanf 行的方式,但我无法让它工作。

这是我正在阅读的结构:

typedef struct Employee
    {
    int ID;
    char salutation[4];
    char firstName[21];
    char surName[31];
    char position[16];
    int sal;
    int deleted;
    } Employee;

【问题讨论】:

  • %s 是贪婪的,我认为,它读取一个完整的单词......它找到%d,整数部分,然后是,,然后它必须读取一个细绳。 , 在字符串中有效,因此它会一直读取到行尾(直到那时没有空格),直到第一个逗号……其余部分保持为空。 (From this answer)
  • 您在帖子中有一个 firstN 和一个 firstName - 是哪个?你也可以发布结构吗?
  • 更正了变量名并添加了结构体

标签: c file-io input scanf


【解决方案1】:

这是因为字符串%s 可以包含逗号,所以它会被扫描到第一个字符串中。 scanf() 格式说明符中没有“前瞻”,%s 后跟格式说明字符串中的逗号这一事实没有任何意义。

使用字符组(搜索 the manual 以获得 [)。

const int got = fscanf(f, "%d,%[^,],%[^,],%[^,],%[^,],%d,%d", &inArray[i].ID,
                       inArray[i].salutation, inArray[i].firstName,
                       inArray[i].surName, inArray[i].position, &inArray[i].sal, 
                       &inArray[i].deleted);

并学会检查返回值,因为 I/O 调用可能会失败!不要依赖数据是否有效,除非 got 为 7。

为了让您的程序读取整个文件(多条记录,即行),我建议将整行加载到带有fgets() 的(大)固定大小的缓冲区中,然后在该缓冲区上使用sscanf() 进行解析列值。这要容易得多,并且可以确保您确实扫描单独的行,在循环中调用 fscanf() 不会,因为对于 fscanf(),换行符只是空格。

【讨论】:

  • 那么你最后说的是我应该把它放在一个while循环中,而得到= 7?
  • @user2368481 实际上没有,我添加了更多文本。
  • 再次感谢您的信息
【解决方案2】:

不妨发表我的评论作为答案:

%s 默认读取一个完整的单词。

它找到%d,整数部分,然后是,,然后它必须读取一个字符串。 , 在一个单词中被认为是有效的(它不是空格),所以它会一直读取到行尾(直到那时没有空格),直到第一个逗号......其余的仍然是空的。 (From this answer)

您必须通过指定正则表达式来更改分隔符:

fscanf(f, "%d,%[^,],%[^,],%[^,],%[^,],%d,%d", &inArray[i].ID, inArray[i].salutation, inArray[i].firstName, inArray[i].surName, inArray[i].position, &inArray[i].sal, &inArray[i].deleted);

不要使用%s,而是使用%[^,],这意味着“获取所有字符,并在找到, 时停止”。

编辑

%[^,]s 不好,在扫描集结束后需要文字 s...谢谢@MichaelPotter

(来自Changing the scanf() delimiterReading values from CSV file into variables

【讨论】:

  • s 应该被删除,因为 [^,] 充当说明符。即:“%[^,]s”应该是“%[^,]”。当它被编码时,scanf 将在每个字段的末尾寻找一个 s。找不到s,scanf将放弃解析。
  • 感谢@MichaelPotter 大脑有时会关闭...这正是结对编程可以带来巨大推动作用的原因...
猜你喜欢
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
相关资源
最近更新 更多