gpt4 book ai didi

c - 如何使用 sscanf 读取带有继续逗号的一行 csv

转载 作者:行者123 更新时间:2023-11-30 16:18:32 25 4
gpt4 key购买 nike

我尝试像这样解析一行 csv 文件

47369758,Ysabel,Rosalie,Matthewson,41,76,47,42,70,83
69054587,Errick,Clareta,,34,67,57,43,27,49
95926740,Gottfried,Farr,Sampson,95,100,61,46,2,85

格式为 id、名字、姓氏、中间名、hw1、hw2、hw3、midterm1、midterm2、final。并且可能没有中间名,如何使用 sscanf 正确读取第二行。

我首先使用getline逐行读取文件,然后将行放入sscanf中进行解析以获取正确的对应值,然后逐个字符读取该行以查看该行是否有连续的逗号,如果有两个逗号则使用没有中间名的 sscanf

    char *line = NULL;
size_t len = 1000;
while(getline(&line, &len, stdin)!= EOF)
{

int idNum, final;
char* firstName = malloc(100);
char* lastName =malloc(100);
char* middleName =malloc(100);
int hw1, hw2, hw3;
int m1, m2;
Student * student = malloc(sizeof(Student));
student->m_scores = malloc(sizeof(Midterms));

int i;
int counter =0;

for (i=0; i< strlen(line); i++){
if(line[i] == ',' && line[i+1] == ',')
{counter++;}
}
printf("counter: %d\n", counter);

if (counter == 1)
{
sscanf(line,"%d ,%[^,],%[^,],%0[^,],%d ,%d,%d,%d,%d,%d\n",&idNum, firstName, lastName,middleName, &hw1, &hw2, &hw3, &m1, &m2, &final);

}
else{

sscanf(line,"%d ,%[^,],%[^,], %[^,],%d ,%d,%d,%d,%d,%d\n",&idNum, firstName, lastName, middleName, &hw1, &hw2, &hw3, &m1, &m2, &final);

}

这是我的代码,用于读取没有中间名的行

sscanf(line,"%d ,%[^,],%[^,],%d ,%d,%d,%d,%d,%d\n",&idNum, firstName, lastName, &hw1, &hw2, &hw3, &m1, &m2, &final);

这是我的代码,用于读取带有中间名的行

sscanf(line,"%d ,%[^,],%[^,], %[^,],%d ,%d,%d,%d,%d,%d\n",&idNum, firstName, lastName, middleName, &hw1, &hw2, &hw3, &m1, &m2, &final);

这是我的实际结果

47369758,Ysabel,Rosalie,Matthewson,41,76,47,42,70,83
69054587,Errick,Clareta,,41,76,47,42,70,83
95926740,Gottfried,Farr,Sampson,95,100,61,46,2,85

这是预期结果

47369758,Ysabel,Rosalie,Matthewson,41,76,47,42,70,83
69054587,Errick,Clareta,,34,67,57,43,27,49
95926740,Gottfried,Farr,Sampson,95,100,61,46,2,85

最佳答案

无论如何,您都需要检查 sscanf() 返回的值。您使用行计数器的技巧本质上是脆弱的,并且无法扩展以处理数十名学生,更不用说数百或数千或更多了。您需要做的更像是:

int rc = sscanf(line, "%d , %[^,], %[^,], %[^,],%d ,%d ,%d ,%d ,%d ,%d",
&idNum, firstName, lastName, middleName, &hw1, &hw2, &hw3, &m1, &m2, &final);
if (rc == 10)
{
/* All present and correct */
}
else if (rc == 3)
{
/* Problem at middle name — presumably it is missing */
rc = sscanf(line, "%d , %[^,], %[^,],,%d ,%d ,%d ,%d ,%d ,%d",
&idNum, firstName, lastName, &hw1, &hw2, &hw3, &m1, &m2, &final);
if (rc != 9)
{
/* Misformatted still — there is an irresolvable problem with this line */
}
else
{
/* All except middle name present and correct */
middlename[0] = '\0';
}
}
else
{
/* Misformatted — there is an irresolvable problem with this line */
}
/* Process information here — unless you did it at the 'present and correct' lines */

当出现无法解决的问题时,您可以报告错误,并引用整行(如果不使用 getline() 加上 sscanf() — 这就是建议使用该组合的原因)。

当不存在无法解决的问题时,您可以继续将数据复制到最近分配的结构中。您可以决定处理更多返回代码,并对数据进行适当的更正。请记住,sscanf() 在第一次失败时停止解析。

所有基于字符串的输入都应该受到限制 - 因为您似乎分配了 100 个字节,所以您应该使用 %99[^,]。您可以考虑名称是否允许包含空格 - 如果不允许,您可以使用 %99[, ] 甚至 %99[^,\t\n] 或类似(并且您可以考虑在扫描集和后面的逗号之间添加一个空格,以便不扫描名称后面的任何尾随空格(就像扫描集之前的空格跳过名称之前的任何空格一样)。可以说,这让处理格式不正确的数据。这并不是一件坏事。(这是 Postel 定律,或 Robustness Principle :该原理也称为 Postel 定律,以 Jon Postel 的名字命名,他在 TCP 的早期规范中写道: TCP 实现应该遵循稳健性的一般原则:对自己所做的事情保持保守,对从他人那里接受的内容保持自由。)

您还可以设计一个基于 strcspn() 的方案来识别逗号之间的字符。您会将每个字段处理为一个字符串,然后在适当的时候将字符串转换为数字(并验证数字:负分数、超过 100 的分数等可能无效)。这是最灵活的方案。它还可以保护您免受整数溢出的影响,而 sscanf() 则不能。

关于c - 如何使用 sscanf 读取带有继续逗号的一行 csv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55876376/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com