如何仅用C语言fscanf()读取逗号分隔的多类型变量
问题:使用fscanf读取带特殊前缀的数值字段
给定格式的文本文件:
a,b,c x,y,z其中a为
char*类型,b为float类型,c为double类型。示例输入文件如下:apple,$12.34,test130.8 x,y,z需要用
fscanf()读取a、b、c并赋值给对应变量:将"apple"赋值给同类型的A;将"12.34"(而非"$12.34")赋值给float类型的B,以此类推。尝试过两种代码:
- 用
%[^,]匹配字段,但%[^,]仅适用于char*类型,无法直接赋值给float/double变量:fp = the file pointer char A[50]; float B; double C; fscanf(fp, "%[^,],%[^,],%[^,]\n", A, B, C);
- 用
%s,%f,%lf格式,但会因b字段的$导致读取异常,B得到0.000000:fscanf(fp, "%s,%f,%lf\n", A, B, C);问题:能否解析
%[^,]使其适配float类型?或者有其他正确读取的方法?
解决方法
方法1:固定前缀时直接跳过
如果数值字段的前缀是固定的(比如示例中的$),可以直接在fscanf格式串中指定跳过该前缀,再读取数值:
#include <stdio.h> int main() { FILE *fp = fopen("test.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } char A[50]; float B; double C; // %[^,]读取A,跳过$后读取float,再读取double int ret = fscanf(fp, "%[^,],$%f,%lf\n", A, &B, &C); if (ret == 3) { printf("A: %s, B: %.2f, C: %.1lf\n", A, B, C); } else { printf("Failed to read all fields\n"); } fclose(fp); return 0; }
方法2:先读字符串再转换数值(通用方案)
如果前缀不固定,可先用%[^,]把数值字段读取到临时字符串,再通过strtof/strtod提取有效数值:
#include <stdio.h> #include <stdlib.h> int main() { FILE *fp = fopen("test.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } char A[50], temp_b[50], temp_c[50]; float B; double C; int ret = fscanf(fp, "%[^,],%[^,],%[^,]\n", A, temp_b, temp_c); if (ret == 3) { // 跳过temp_b中的非数值字符,定位到数字起始位置 char *num_start = temp_b; while (*num_start != '\0' && !((*num_start >= '0' && *num_start <= '9') || *num_start == '.')) { num_start++; } B = strtof(num_start, NULL); // 同理处理C字段 num_start = temp_c; while (*num_start != '\0' && !((*num_start >= '0' && *num_start <= '9') || *num_start == '.')) { num_start++; } C = strtod(num_start, NULL); printf("A: %s, B: %.2f, C: %.1lf\n", A, B, C); } else { printf("Failed to read all fields\n"); } fclose(fp); return 0; }
方法3:用格式控制跳过非数值字符
利用fscanf的%*[...]匹配并忽略非数值字符,直接读取后面的数值:
#include <stdio.h> int main() { FILE *fp = fopen("test.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } char A[50]; float B; double C; // %[^,]读取A,%*[^0-9.]跳过所有非数字/小数点字符,再读取数值 int ret = fscanf(fp, "%[^,],%*[^0-9.]%f,%*[^0-9.]%lf\n", A, &B, &C); if (ret == 3) { printf("A: %s, B: %.2f, C: %.1lf\n", A, B, C); } else { printf("Failed to read all fields\n"); } fclose(fp); return 0; }
注:%*[...]中的*表示匹配该模式但不存储到变量中,适合处理任意前缀的场景。
内容的提问来源于stack exchange,提问作者Minrui L
相关产品推荐
相关产品推荐

