首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有可选/空格式说明符的分析帧

带有可选/空格式说明符的分析帧
EN

Stack Overflow用户
提问于 2018-06-14 11:38:30
回答 3查看 668关注 0票数 3

我试图解析按以下方案格式化的帧:

代码语言:javascript
运行
复制
$[number],[number],[number],<string>;[string]~<string>

被'[]‘包围的参数是可选的,而那些被'<>’包围的参数总是存在定义的:

因此,下列框架都是正确的:

代码语言:javascript
运行
复制
$0,0,0,thisIsFirstString;secondString~thirdOne
$0,,0,firstString;~thirdOne
$,,,firstString;~thirdString

当前,当所有元素都有以下代码时,我能够解析框架

代码语言:javascript
运行
复制
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;
}

有以下结果

代码语言:javascript
运行
复制
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

但是,如果缺少一个参数,则前面的参数将被很好地解析,而那些在缺少参数之后的参数则不会被解析。

代码语言:javascript
运行
复制
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 指定帧中可能缺少的一些参数,以便在这种情况下它们将被丢弃?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-06-14 12:28:45

正如其他人所说的那样,scanf()家族函数可能不适合这样做,因为在输入字符串不符合预期格式的情况下,不可能进行足够的错误处理。

但是,如果您确信输入字符串将始终是该格式,则可以使用指向输入字符串的相关部分的指针,然后用sscanf()处理该部分。

首先,将所有字符数组初始化为空字符串,以便它们在打印时不会显示垃圾。喜欢

代码语言:javascript
运行
复制
char num1[10]="";

对于所有要将提取的参数写入其中的char数组。

声明一个字符指针并使其指向frame的开头,这是输入字符串。

代码语言:javascript
运行
复制
char *ptr=frame;

现在检查第一个参数,它是可选的,如

代码语言:javascript
运行
复制
if(sscanf(ptr, "$%[^,],", num1)==1)
{
    //parameter 1 is present.
    ptr+=strlen(num1);  
}
ptr+=2;

如果存在参数,则用参数字符串的长度递增ptr,并对'$‘和逗号进行进一步的2增量。

同样,对于后面的两个参数也是可选的。

代码语言:javascript
运行
复制
if(sscanf(ptr, "%[^,]", num2)==1)
{
    //Parameter 2 is present
    ptr+=strlen(num2);  
}
ptr+=1;

if(sscanf(ptr, "%[^,]", num3)==1)
{
    //Parameter 3 is present
    ptr+=strlen(num3);  
}
ptr+=1;

下一个参数参数4不是可选的。

代码语言:javascript
运行
复制
sscanf(ptr, "%[^;]", str1);
ptr+=strlen(str1)+1;

对于可选参数5,

代码语言:javascript
运行
复制
if(sscanf(ptr, "%[^~]", str2)==1)
{
    //Parameter 5 is present
    ptr+=strlen(str2);  
}
ptr+=1; //for ~

最后,对于非可选参数6,

代码语言:javascript
运行
复制
sscanf(ptr, "%s", str3);

为了简洁起见,省略了可能的错误检查。若要防止溢出,请在scanf()格式字符串中使用宽度说明符,如

代码语言:javascript
运行
复制
sscanf(ptr, "%9[^,],", num2);

其中,9num2字符数组的长度少一个。

在您的程序中,如果sscanf()部件对应于空字符串,则%[^,]实际上停止为变量分配。

票数 1
EN

Stack Overflow用户

发布于 2018-06-14 12:26:55

最好的方法仍然是编写自己的解析器函数:

代码语言:javascript
运行
复制
#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;
}

输入如下:

代码语言:javascript
运行
复制
$0,0,0,thisIsFirstString;secondString~thirdOne
$0,,0,firstString;~thirdOne
$,,,firstString;~thirdString

产生的结果:

代码语言:javascript
运行
复制
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`
票数 2
EN

Stack Overflow用户

发布于 2018-06-14 15:06:56

scanf()不能转换句柄空字符类,而且strtok()将每个分隔符序列看作一个分隔符,这实际上只适合于空白。

下面是一个简单的、类似扫描的非贪婪解析器:

代码语言:javascript
运行
复制
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

int my_sscanf(const char *s, const char *fmt, ...) {
    int res = 0;
    va_list ap;

    va_start(ap, fmt);
    for (; *fmt; fmt++) {
        if (*fmt == '%') {
            fmt++;
            if (*fmt == 's') {
                size_t i = 0, size = va_arg(ap, size_t);
                char *dest = va_arg(ap, char *);

                while (*s && *s != fmt[1]) {
                    if (i + 1 < size)
                        dest[i++] = *s;
                    s++;
                }
                if (size)
                    dest[i] = '\0';
                res++;
                continue;
            }
            if (*fmt == 'd') {
                *va_arg(ap, int *) = strtol(s, (char **)&s, 10);
                res++;
                continue;
            }
            if (*fmt == 'i') {
                *va_arg(ap, int *) = strtol(s, (char **)&s, 0);
                res++;
                continue;
            }
            /* add support for other conversions as you wish */
            if (*fmt != '%')
                return -1;
        }
        if (*fmt == ' ') {
            while (isspace((unsigned char)*s))
                s++;
            continue;
        }
        if (*s == *fmt) {
            s++;
        } else {
            break;
        }
    }
    va_end(ap);
    return res;
}

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

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

    res = my_sscanf(frame, "$%d,%d,%d,%s;%s~%s", &num1, &num2, &num3,
                    sizeof str1, str1, sizeof str2, str2, sizeof str3, str3);

    if (res == 6) {
        printf("Number 1 : %d\n", num1);
        printf("Number 2 : %d\n", num2);
        printf("Number 3 : %d\n", num3);
        printf("String 1 : %s\n", str1);
        printf("String 2 : %s\n", str2);
        printf("String 3 : %s\n", str3);
    } else {
        printf("my_scanf returned %d\n", res);
    }
    return 0;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50856696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档