sscanf多字符串扫描

时间:2018-12-19 11:50:28

标签: c scanf

我想用sscanf在c中捕获以下字符串

"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"

但是sscanf仅用{Salam Khobi“填充&customInput.typecustomInputTitle[0],而字符串的其他部分则不会扫描。

 #include <stdio.h>
#include <stdlib.h>

typedef enum {
    INPUT_NUMBER = 0,
    INPUT_NORMAL = 1,
    INPUT_PASSWORD = 2,
    INPUT_PAYAMOUNT = 3,
} inputType;

typedef struct {
    char * title[2];
    char * extra[2];
    inputType type;
    unsigned minLen:6;
    unsigned maxLen:6;
    unsigned forceLen:1;
    unsigned editable:1;
    unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH     40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
#define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
static lcdInput customInput = {
        .title = {&customInputTitle[0], &customInputTitle[1]},
        .extra = {&customInputExtra[0], &customInputExtra[1]},
        .type = INPUT_NORMAL,
        .editable = 1,
        .forceLen = 0,
};

int main()
{
    memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
    memset(&customInputExtra, 0, CUSTOM_INPUT_LENGTH << 1);

    sscanf(payload, CUSTOM_INPUT_REGX,
           &customInput.type,
           &customInputTitle[0], &customInputTitle[1],
           &customInputExtra[0], &customInputExtra[1]);

    return 0;
}

2 个答案:

答案 0 :(得分:1)

select hll_set_defaults(17,5,-1,1); 是正确的格式。

答案 1 :(得分:1)

问的问题

在scanset伪指令|遇到%[^|]字符后,sscanf()将恢复与|字符的匹配。下一条指令应为文字|,以避免匹配失败。在原始代码中,对于%[^|]ss不是scanset指令的一部分,而是sscanf()试图匹配文字{{1} }。另外,请注意,应始终将最大宽度说明符与s%s %[]系列指令一起使用,以避免由于恶意或格式错误的输入而导致缓冲区溢出:

fscanf()

其他一些严重问题

在编译C代码时始终启用警告;这样做可以帮助您避免几个严重的问题。此代码有很多警告,并且下面列出的大多数问题都导致未定义的行为。我总是至少使用"%d=%39[^|]|%39[^=]=%39[^|]|%39s" ,并在答案的末尾添加了原始代码的gcc输出示例。

gcc -std=c11 -Wall -Wextra -Wpedantic中缺少发布的代码#include <string.h>

memset()的{​​{1}}和.title字段应为.extra,因为它们指向lcdInput数组的首个元素。

unsigned char *的初始化中,unsigned char运算符应被删除。 customInput&都期望有指向customInput.title(或在上述更正之前的customInput.extra)的指针。与,例如unsigned char有一个指向char &customInputTitle[0] s(或在上述更正之前的CUSTOM_INPUT_LENGTH s)数组的指针;这是类型不匹配,您的编译器应大声抱怨(启用警告)。相反,只需使用:

unsigned char

在这里,charstatic lcdInput customInput = { .title = {customInputTitle[0], customInputTitle[1]}, .extra = {customInputExtra[0], customInputExtra[1]}, .type = INPUT_NORMAL, .editable = 1, .forceLen = 0, }; customInputTitle[0]个数组,它们将衰减为指向其第一个元素(CUSTOM_INPUT_LENGTH)的指针。另外,您可以使用unsigned charunsigned char *

类似地,您需要在对&customInputTitle[0][0]的调用中从&customInputTitle[1][0]数组中删除与号。在这里,您还需要对customInput做一些事情。这是sscanf()类型,您不能输入&customInput.type值。同样,编译器抱怨启用了警告。相反,请尝试:

enum

此处使用enum来收集输入,检查int typeInput; if (sscanf(payload, CUSTOM_INPUT_REGX, &typeInput, customInputTitle[0], customInputTitle[1], customInputExtra[0], customInputExtra[1]) == 5) { if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) { customInput.type = typeInput; } else { /* Handle error */ } }; 返回的值以验证是否分配了正确的值数量,并针对typeInput的值进行检查。 sscanf()的值范围。如果输入符合预期,则将typeInput分配给inputType

typeInput的调用将起作用,但是为什么用位移来混淆事物呢?您也不需要customInput.type运算符,但是在这种情况下,它们可以。相反,请考虑:

memset()

这是更正的代码。使用&编译时没有警告:

memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);

带有警告的GCC输出

以下是问题中发布的原始程序中带有gcc -std=c11 -Wall -Wextra -Wpedantic的编译器警告:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>        // missing header

typedef enum {
    INPUT_NUMBER = 0,
    INPUT_NORMAL = 1,
    INPUT_PASSWORD = 2,
    INPUT_PAYAMOUNT = 3,
} inputType;

typedef struct {
    unsigned char * title[2];    // need unsigned char
    unsigned char * extra[2];
    inputType type;
    unsigned minLen:6;
    unsigned maxLen:6;
    unsigned forceLen:1;
    unsigned editable:1;
    unsigned char data[100];
} lcdInput;

#define CUSTOM_INPUT_LENGTH     40

static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";

// bad format string
#define CUSTOM_INPUT_REGX       "%d=%39[^|]|%39[^=]=%39[^|]|%39s"

// & operator not needed
static lcdInput customInput = {
    .title = {customInputTitle[0], customInputTitle[1]},
    .extra = {customInputExtra[0], customInputExtra[1]},
    .type = INPUT_NORMAL,
    .editable = 1,
    .forceLen = 0,
};

int main(void)
{
    // could use improvements
    memset(customInputTitle, 0, sizeof customInputTitle);
    memset(customInputExtra, 0, sizeof customInputExtra);

    // & operators not needed
    int typeInput;
    if (sscanf(payload, CUSTOM_INPUT_REGX,
               &typeInput,
               customInputTitle[0], customInputTitle[1],
               customInputExtra[0], customInputExtra[1]) == 5) {
        if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
            customInput.type = typeInput;
        } else {
            /* Handle error */
        }
    };

    return 0;
}