You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言解析ASCII文件键值对:sscanf格式串问题咨询

问题背景

需要编写C函数读取ASCII文件中的键值对,文件规则如下:

  • 忽略以[、!、$开头的行
  • =前后可能存在0个或多个空格
  • 值可以是字符串或数字
  • 键值对后的$及后续内容需忽略

现有代码使用sscanf无法匹配无空格的键值对(如param_1=123),输出缺失该部分内容。

文件内容

[SECTION 1 HEADER - ignore this line]
VAR1             =   'xyz'
VAR2          =   3.0
VARIAB3           =   'blabla'
! COMMENT: ignore this line              VAR7 =      'ABC123'
$---------another line to ignore----------------- 
[SECTION 2 HEADER - ignore me!]
varname8                =        'abcd'
$---------yet another line to ignore-----------
[SECTION HEADER - ignore me]
VARIABLE10 =    4.05101e+05      $ignore from the dollar sign to eol
VARIABLE13 =    7e-06      $ignore from the dollar sign to eol
param_1=123
param_2=321

原有代码

fh = fopen(filename, "r");
if(NULL == fh) {
    perror(filename);
}
else
{
    printf("File opened succesfully.\n");
    while(fgets(buffer, 100, fh) != NULL)
    {
        {
            int offset;
            int res = sscanf(buffer, "%s = %s%n", key, value, &offset);
            if(res==2)
            {
                printf("Found: %s = %s\n", key, value);
            }
        }   
    }
}

原有输出

Filename is: sample.tir
File opened succesfully.
Found: VAR1 = 'xyz'
Found: VAR2 = 3.0
Found: VARIAB3 = 'blabla'
Found: varname8 = 'abcd'
Found: VARIABLE10 = 4.05101e+05
Found: VARIABLE13 = 7e-06
File closed.
问题原因

原sscanf格式串"%s = %s%n"强制要求=前后必须有空格:

  • %s会读取到第一个空格为止,对于param_1=123,%s会把整个param_1=123当作键读取,后续找不到匹配的=,导致返回值不等于2,无法触发输出逻辑。
修正方案

1. 优化sscanf格式串,支持=前后无空格

使用灵活的格式匹配规则,适配=前后有无空格的场景:

int res = sscanf(buffer, "%[^=]%*[ =]%[^$]", key, value);
  • %[^=]:匹配所有非=的字符,读取键(会包含键前的空格,后续需修剪)
  • %*[ =]:跳过任意数量的空格和=符号,*表示只匹配不存储
  • %[^$]:匹配所有非$的字符,读取值(会包含值后的空格,后续需修剪)

2. 先过滤无效行

在处理每行前直接跳过规则要求忽略的行,避免无效匹配:

// 跳过空白行和开头为[、!、$的行
if (buffer[0] == '\0' || buffer[0] == '[' || buffer[0] == '!' || buffer[0] == '$') {
    continue;
}

3. 修剪键和值的前后空白

因为格式串会读取到键前、值后的空格,需要手动修剪:

// 实现空白修剪函数
char* trim_whitespace(char *str) {
    // 去掉开头空格
    while(isspace((unsigned char)*str)) str++;
    if(*str == 0) return str;
    // 去掉结尾空格
    char *end = str + strlen(str) - 1;
    while(end > str && isspace((unsigned char)*end)) end--;
    // 添加字符串结束符
    *(end + 1) = '\0';
    return str;
}

完整修正代码

#include <stdio.h>
#include <string.h>
#include <ctype.h>

char* trim_whitespace(char *str) {
    while(isspace((unsigned char)*str)) str++;
    if(*str == 0) return str;
    char *end = str + strlen(str) - 1;
    while(end > str && isspace((unsigned char)*end)) end--;
    *(end + 1) = '\0';
    return str;
}

int main(int argc, char *argv[]) {
    if(argc < 2) {
        printf("Usage: %s <filename>\n", argv[0]);
        return 1;
    }
    const char *filename = argv[1];
    FILE *fh = fopen(filename, "r");
    if(NULL == fh) {
        perror(filename);
        return 1;
    }
    
    printf("File opened successfully.\n");
    char buffer[100];
    char key[100], value[100];
    while(fgets(buffer, sizeof(buffer), fh) != NULL) {
        // 跳过无效行
        if (buffer[0] == '\0' || buffer[0] == '[' || buffer[0] == '!' || buffer[0] == '$') {
            continue;
        }
        
        // 匹配键值对,支持=前后无空格,忽略$后的内容
        int res = sscanf(buffer, "%[^=]%*[ =]%[^$]", key, value);
        if(res == 2) {
            trim_whitespace(key);
            trim_whitespace(value);
            printf("Found: %s = %s\n", key, value);
        }
    }
    
    fclose(fh);
    printf("File closed.\n");
    return 0;
}
测试结果

运行修正后的代码,会输出所有符合规则的键值对:

File opened successfully.
Found: VAR1 = 'xyz'
Found: VAR2 = 3.0
Found: VARIAB3 = 'blabla'
Found: varname8 = 'abcd'
Found: VARIABLE10 = 4.05101e+05
Found: VARIABLE13 = 7e-06
Found: param_1 = 123
Found: param_2 = 321
File closed.

内容的提问来源于stack exchange,提问作者picchiolu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:25:24