C语言实现CSV地震数据筛选遇问题,求筛选逻辑及代码修正
地震数据CSV筛选代码修正与逻辑说明
我有一份存储地震数据的CSV文件,想要实现让用户按日期范围、城市、区域、里氏震级筛选数据并打印结果的功能。已经定义了结构体,尝试用strtok处理CSV的逗号分隔,但代码报错多,也没理清筛选逻辑。附上问题代码和CSV文件截图,求修正代码并明确筛选逻辑。
问题代码(原始错误版本)
int sorgu(){ FILE *fp; //dosya pointer'ı fp = fopen("/Users/Desktop/earthquake.csv" , "r"); int val=0; int min=0; int max=0; char *sp; //string pointer char line[LINE]; int filtre=0; struct earthquake; printf("***For which element do you want to filter?*** "); printf("PRESS 1 FOR DATE RANGE. "); printf("PRESS 2 FOR CITY. "); printf("PRESS 3 FOR DISTRICT. "); printf("PRESS 4 FOR RICHTER VALUE. "); scanf("%d" , &val); switch(filtre){ case 1: printf("Enter the lower value for year."); scanf("%d" , &min); printf("Enter the upper value for year."); scanf("%d" , &max); while(fgets(line, LINE, fp) != NULL){ sp=strtok(line, ","); //string başından ilk virgülü görene kadar struct earthquake.id = atoi(sp); //id değerini int değere çevirip earthquake.id'ye atar sp=strtok(NULL, ","); //kaldığı virgülden itibaren diğer virgüle kadar strcpy(earthquake.date, sp); //sp'yi earthquake.date'e kopyalar if(min<=date.upLimit && max>=date.topLimit){ printf("Earthquakes in the range you specify: " , ); } } } fclose(fp); }
CSV文件截图

修正后的完整代码
#define LINE 1024 // 匹配CSV列的结构体定义 struct earthquake { int id; char date[20]; char time[20]; double latitude; double longitude; double depth; double magnitude; char city[50]; char district[50]; }; int sorgu(){ FILE *fp; int val = 0; int min_year = 0, max_year = 0; char *sp; char line[LINE]; struct earthquake eq; char filter_str[50]; double min_mag = 0, max_mag = 0; // 文件打开错误检查 fp = fopen("/Users/Desktop/earthquake.csv", "r"); if (fp == NULL) { printf("无法打开文件!\n"); return -1; } printf("***请选择筛选条件***\n"); printf("1 - 日期范围(按年份筛选)\n"); printf("2 - 城市\n"); printf("3 - 区域\n"); printf("4 - 里氏震级\n"); scanf("%d", &val); getchar(); // 吸收输入后的换行符 // 跳过CSV表头行 fgets(line, LINE, fp); switch(val) { case 1: printf("请输入起始年份:"); scanf("%d", &min_year); printf("请输入结束年份:"); scanf("%d", &max_year); getchar(); printf("您指定范围内的地震数据:\n"); while(fgets(line, LINE, fp) != NULL) { sp = strtok(line, ","); eq.id = atoi(sp); sp = strtok(NULL, ","); strcpy(eq.date, sp); // 从DD.MM.YYYY格式中提取年份 char *year_str = strrchr(eq.date, '.') + 1; int year = atoi(year_str); if (year >= min_year && year <= max_year) { printf("%s", line); } } break; case 2: printf("请输入要筛选的城市名称:"); fgets(filter_str, sizeof(filter_str), stdin); filter_str[strcspn(filter_str, "\n")] = '\0'; // 去掉换行符 printf("匹配该城市的地震数据:\n"); while(fgets(line, LINE, fp) != NULL) { // 跳过前7列,定位到城市列 sp = strtok(line, ","); for(int i=0; i<7; i++) { sp = strtok(NULL, ","); } strcpy(eq.city, sp); if (strcmp(eq.city, filter_str) == 0) { printf("%s", line); } } break; case 3: printf("请输入要筛选的区域名称:"); fgets(filter_str, sizeof(filter_str), stdin); filter_str[strcspn(filter_str, "\n")] = '\0'; printf("匹配该区域的地震数据:\n"); while(fgets(line, LINE, fp) != NULL) { // 跳过前8列,定位到区域列 sp = strtok(line, ","); for(int i=0; i<8; i++) { sp = strtok(NULL, ","); } strcpy(eq.district, sp); if (strcmp(eq.district, filter_str) == 0) { printf("%s", line); } } break; case 4: printf("请输入最小震级:"); scanf("%lf", &min_mag); printf("请输入最大震级:"); scanf("%lf", &max_mag); getchar(); printf("震级范围内的地震数据:\n"); while(fgets(line, LINE, fp) != NULL) { // 跳过前6列,定位到震级列 sp = strtok(line, ","); for(int i=0; i<6; i++) { sp = strtok(NULL, ","); } eq.magnitude = atof(sp); if (eq.magnitude >= min_mag && eq.magnitude <= max_mag) { printf("%s", line); } } break; default: printf("无效的选择!\n"); break; } fclose(fp); return 0; }
核心修正点与筛选逻辑说明
代码修正点
- 结构体使用修正:补充完整结构体定义,定义结构体变量
eq,通过变量正确访问成员 - 文件操作修正:增加
fopen失败的错误判断,避免空指针操作;跳过CSV表头行,避免处理标题数据 - 分支变量修正:
switch使用用户输入的val而非未赋值的filtre - 输入处理修正:用
getchar()吸收换行符,避免fgets读取空行;对用户输入的字符串去掉换行符 - 格式错误修正:修复
printf的无效格式问题,改为直接打印匹配的CSV行
筛选逻辑说明
- 日期范围筛选:从CSV的日期字符串(格式
DD.MM.YYYY)中提取年份,转为整数后与用户输入的起止年份比较,保留年份在区间内的数据 - 城市/区域筛选:定位到CSV对应的城市/区域列,将列字符串与用户输入的关键词做精确匹配(如需模糊匹配可改用
strstr函数),保留匹配成功的数据 - 里氏震级筛选:将CSV的震级列转为浮点数,与用户输入的震级区间比较,保留震级在区间内的数据
内容的提问来源于stack exchange,提问作者keeprunnin
相关产品推荐
相关产品推荐

