c - sscanf - 带有可选/空格式说明符的解析帧

标签 c parsing scanf optional-parameters format-specifiers

我正在尝试解析按以下方案格式化的帧:

$[number],[number],[number],<string>;[string]~<string>

用'[]'包围的参数是可选的,用'<>'包围的参数总是存在定义的:

因此,下面的帧都是正确的:

$0,0,0,thisIsFirstString;secondString~thirdOne
$0,,0,firstString;~thirdOne
$,,,firstString;~thirdString

目前,当所有元素都存在时,我可以使用以下代码解析框架

int main() {
    char frame[100] = "$1,2,3,string1;string2~string3";
    char num1[10], num2[10], num3[10], str1[100], str2[100], str3[100];

    printf("frame : %s\n", frame);

    sscanf(frame,"$%[^,],%[^,],%[^,],%[^;];%[^~]~%s", num1, num2, num3, str1, str2, str3);

    printf("Number 1 : %s\n", num1);
    printf("Number 2 : %s\n", num2);
    printf("Number 3 : %s\n", num3);
    printf("String 1 : %s\n", str1);
    printf("String 2 : %s\n", str2);
    printf("String 3 : %s\n", str3);

    return 0;
}

结果如下

frame : $1,2,3,string1;string2~string3
Number 1 : 1
Number 2 : 2
Number 3 : 3
String 1 : string1
String 2 : string2
String 3 : string3

但是,如果缺少一个参数,前面的参数会被很好地解析,但缺少参数后面的参数不会被解析。

frame : $1,,3,string1;string2~string3
Number 1 : 1
Number 2 : 
Number 3 : 
String 1 :��/�
String 2 : �\<��
String 3 : $[<��

frame : $1,2,3,string1;~string3
Number 1 : 1
Number 2 : 2
Number 3 : 3
String 1 : string1
String 2 : h�v��
String 3 : ��v��

我如何向 sscanf 指定帧中可能缺少某些参数,以便在这种情况下将丢弃它们?

最佳答案

猜测最好的还是自己写解析器函数:

#define _GNU_SOURCE 1
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

#define __arraycount(x) (sizeof(x)/sizeof(x[0]))

// from https://stackoverflow.com/a/3418673/9072753
static char *mystrtok(char **m,char *s,char c)
{
  char *p = s ? s : *m;
  if (!*p)
    return NULL;
  *m = strchr(p, c);
  if (*m)
    *(*m)++ = '\0';
  else
    *m = p + strlen(p);
  return p;
}

static char getseparator(size_t i)
{
    return i <= 2 ? ',' : i == 3 ? ';' : i == 4 ? '~' : 0;
}

int main()
{
    char ***output = NULL;
    size_t outputlen = 0;
    const size_t outputstrings = 6;

    char *line = NULL;
    size_t linelen = 0;
    size_t linecnt;
    for (linecnt = 0; getline(&line, &linelen, stdin) > 0; ++linecnt) {
        if (line[0] != '$') {
            printf("Lines not starting with $ are ignored\n");
            continue;
        }

        // alloc memory for new set of 6 strings
        output = realloc(output, sizeof(*output) * outputlen++);
        if (output == NULL) {
            fprintf(stderr, "%d Error allocating memory", __LINE__);
            return -1;
        }
        output[outputlen - 1] = malloc(sizeof(*output[outputlen - 1]) * outputstrings);
        if (output[outputlen - 1] == NULL) {
            fprintf(stderr, "%d Error allocating memory", __LINE__);
            return -1;
        }

        // remove closing newline
        line[strlen(line)-1] = '\0';

        //printf("Read line `%s`\n", line);

        char *token;
        char *rest = &line[1];
        char *state;
        size_t i;
        for (i = 0, token = mystrtok(&state, &line[1], getseparator(i)); 
                i < outputstrings && token != NULL;
                ++i, token = mystrtok(&state, NULL, getseparator(i))) {
            output[outputlen - 1][i] = strdup(token);
            if (output[outputlen - 1][i] == NULL) {
                fprintf(stderr, "%d Error allocating memory", __LINE__);
                return -1;
            }
            //printf("Read %d string: `%s`\n", i, output[outputlen - 1][i]);
        }
        if (i != outputstrings) {
            printf("Malformed line: %s %d %p \n", line, i, token);
            continue;
        }
    }
    free(line);

    for (size_t i = 0; i < outputlen; ++i) {
        for (size_t j = 0; j < outputstrings; ++j) {
            printf("From line %d the string num %d: `%s`\n", i, j, output[i][j]);
        }
    }

    for (size_t i = 0; i < outputlen; ++i) {
        for (size_t j = 0; j < outputstrings; ++j) {
            free(output[i][j]);
        }
        free(output[i]);
    }
    free(output);

    return 0;
}

对于输入:

$0,0,0,thisIsFirstString;secondString~thirdOne
$0,,0,firstString;~thirdOne
$,,,firstString;~thirdString

产生结果:

From line 0 the string num 0: `0`
From line 0 the string num 1: `0`
From line 0 the string num 2: `0`
From line 0 the string num 3: `thisIsFirstString`
From line 0 the string num 4: `secondString`
From line 0 the string num 5: `thirdOne`
From line 1 the string num 0: `0`
From line 1 the string num 1: ``
From line 1 the string num 2: `0`
From line 1 the string num 3: `firstString`
From line 1 the string num 4: ``
From line 1 the string num 5: `thirdOne`
From line 2 the string num 0: ``
From line 2 the string num 1: ``
From line 2 the string num 2: ``
From line 2 the string num 3: `firstString`
From line 2 the string num 4: ``
From line 2 the string num 5: `thirdStrin`

关于c - sscanf - 带有可选/空格式说明符的解析帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50856696/

相关文章:

更改 wav 文件的采样率和比特率而不会遇到打开文件的问题?

c - `strtod("3ex", &end )` supposed to be? What about ` sscanf` 的结果是什么?

c - 欧拉项目#3 : Why is it telling me that this division breaks even when it doesn't?

c - 传递“getGradesFromFile”的参数 1 从指针生成整数,无需强制转换

python - 如何从 python 中的 HTML 表格中的特定单元格获取数据?

Javascript - 控制台成功打印我的数据时出现未捕获的 ReferenceError : azZkVUpgbG is not defined,

c - 关于 C 中 scanf() 的问题

无法扫描C 中的文件

比较 C 中的结构

python - 解析 XML 时出现标签不匹配错误?