C语言中fscanf读取CSV文件出错:多词国家名场景问题
问题描述
我正在制作世界杯球队的链表,预加载阶段需要从CSV文件读取数据,但读取包含多词的国家名时出现错误。
示例CSV内容:
Arabia Saudita, Herve, Renard, Salman, C, 0, 1
实际读取输出:
Country:Arabia DT:Saudita Herve Renard Salman C 0 1 Captain: empty Group:Empty
预期输出:
Country: Arabia Saudita DtName:Herve DtSurname:Renard CaptainName:Salman Group: C
尝试用TXT文件也出现同样问题,因为fscanf会以空格作为分隔符,导致数据错位。以下是出错的代码片段:
FILE *chargue = fopen("Precharge.csv", "r"); while (!feof(charge)) { fscanf(charge, "%s", countryAux); chargecountry(&team, countryAux); fscanf(charge, "%s", nameDTAux); fscanf(charge, "%s", surnameDTAux); chargenameDT(&team, surnameDTAux, nameDTAux); chargeCapitan(&team, nameCapaux); fscanf(charge, "%c", &groupAux); chargegropu(&team, groupAux); fscanf(charge, "%d", &actualscoreaux); chargeactualscore(&team, actualscoreaux); fscanf(charge, "%d", &faseActualaux); chargeFase(&team, faseActualaux); insert(lis, team); forwards(lis); }
解决方案
核心问题是fscanf的%s格式符会以**任意空白字符(空格、换行、制表符)**作为字段分隔,但你的CSV是用逗号分隔的,且部分字段(如国家名)包含空格,必须按逗号来分割字段。
方法1:用fgets读取整行,再用strtok分割(推荐)
先读取整行数据到缓冲区,再以, (逗号加空格)作为分隔符拆分每个字段,能正确保留含空格的国家名:
#include <string.h> // ... FILE *chargue = fopen("Precharge.csv", "r"); char line[256]; // 假设每行数据不超过256字符 while (fgets(line, sizeof(line), chargue) != NULL) { // 去掉换行符 line[strcspn(line, "\n")] = '\0'; // 分割字段:注意CSV分隔符是", "(逗号加空格) char *token = strtok(line, ", "); if (token != NULL) { strncpy(countryAux, token, sizeof(countryAux)-1); countryAux[sizeof(countryAux)-1] = '\0'; // 确保字符串终止 chargecountry(&team, countryAux); } token = strtok(NULL, ", "); if (token != NULL) { strncpy(nameDTAux, token, sizeof(nameDTAux)-1); nameDTAux[sizeof(nameDTAux)-1] = '\0'; } token = strtok(NULL, ", "); if (token != NULL) { strncpy(surnameDTAux, token, sizeof(surnameDTAux)-1); surnameDTAux[sizeof(surnameDTAux)-1] = '\0'; chargenameDT(&team, surnameDTAux, nameDTAux); } token = strtok(NULL, ", "); if (token != NULL) { strncpy(nameCapaux, token, sizeof(nameCapaux)-1); nameCapaux[sizeof(nameCapaux)-1] = '\0'; chargeCapitan(&team, nameCapaux); } token = strtok(NULL, ", "); if (token != NULL) { groupAux = token[0]; // 分组是单个字符 chargegropu(&team, groupAux); } token = strtok(NULL, ", "); if (token != NULL) { actualscoreaux = atoi(token); chargeactualscore(&team, actualscoreaux); } token = strtok(NULL, ", "); if (token != NULL) { faseActualaux = atoi(token); chargeFase(&team, faseActualaux); } insert(lis, team); forwards(lis); } fclose(chargue);
方法2:用sscanf的自定义格式匹配
如果不想用strtok,可以直接用sscanf指定匹配到逗号前的内容,格式字符串中用%[^,]来匹配任意非逗号字符(包括空格):
FILE *chargue = fopen("Precharge.csv", "r"); // 注意格式中的", ":匹配逗号加空格的分隔符 while (sscanf(chargue, "%[^,], %[^,], %[^,], %[^,], %c, %d, %d", countryAux, nameDTAux, surnameDTAux, nameCapaux, &groupAux, &actualscoreaux, &faseActualaux) == 7) { chargecountry(&team, countryAux); chargenameDT(&team, surnameDTAux, nameDTAux); chargeCapitan(&team, nameCapaux); chargegropu(&team, groupAux); chargeactualscore(&team, actualscoreaux); chargeFase(&team, faseActualaux); insert(lis, team); forwards(lis); // 处理换行符(避免下一次读取时残留) while (fgetc(chargue) != '\n' && !feof(chargue)); } fclose(chargue);
注意:%[^,]会读取直到遇到逗号的所有字符,包括空格,刚好适配带空格的国家名;同时要确保每个缓冲区(如countryAux)的大小足够容纳最长的字段内容,避免缓冲区溢出。
额外注意事项
- 不要用
while (!feof(charge)):feof只有在读取到文件末尾后才会触发,会导致最后一行被重复读取,改用fgets或sscanf的返回值判断循环结束更可靠。 - 缓冲区要留足空间,最好用
strncpy代替直接赋值,避免字符串溢出。
内容的提问来源于stack exchange,提问作者Kalifeh
相关产品推荐
相关产品推荐

