首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >扫描多字串扫描

扫描多字串扫描
EN

Stack Overflow用户
提问于 2018-12-19 11:50:27
回答 2查看 169关注 0票数 0

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

代码语言:javascript
复制
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"

但是scan只使用"Salam“填充&customInput.typecustomInputTitle[0],而字符串的其他部分则不会扫描。

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

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-19 12:04:46

"%d=%[^|]|%[^=]=%[^|]|%s"是正确的格式。

票数 1
EN

Stack Overflow用户

发布于 2018-12-19 13:59:57

问题被问到了

当一个|字符被扫描集指令%[^|]遇到后,sscanf()将恢复与|字符的匹配。下一个指令应该是一个文字|,以避免匹配失败。在原始代码中,使用%[^|]s时,s不是扫描集指令的一部分,相反,sscanf()试图在输入中匹配一个文字s。另外,请注意,应始终在%s%[] fscanf()系列指令中使用最大宽度说明符,以避免恶意或格式错误输入的缓冲区溢出:

代码语言:javascript
复制
"%d=%39[^|]|%39[^=]=%39[^|]|%39s"

其他一些严重问题

在编译C代码时始终启用警告;这样做可以帮助您避免几个严重的问题。对于这段代码有很多警告,下面列出的大多数问题都会导致未定义的行为。我总是至少使用gcc -std=c11 -Wall -Wextra -Wpedantic,并且在答案的末尾为原始代码添加了gcc输出的示例。

发布的代码缺少#include <string.h> for memset()

.title.extra字段的lcdInput应该是unsigned char *,因为它们指向unsigned char数组的第一个元素。

customInput的初始化过程中,应该删除&操作符。customInput.titlecustomInput.extra都期望指向unsigned char (或在上述更正之前的chars )的指针。例如,对于&customInputTitle[0],您有一个指向CUSTOM_INPUT_LENGTH unsigned chars数组的指针(或在上面更正之前的chars );这是类型不匹配,编译器应该发出响亮的抱怨(启用了警告)。相反,只需使用:

代码语言:javascript
复制
static 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 char的数组,它将衰减到指向其第一个元素(unsigned char *)的指针。或者,您可以使用&customInputTitle[0][0]&customInputTitle[1][0]等。

类似地,您需要在调用customInput时从sscanf()数组中移除这些符号。在这里,您还需要对&customInput.type做些什么。这是一个enum类型,不能输入enum值。同样,编译器会在启用警告时发出抱怨。相反,试着:

代码语言:javascript
复制
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()返回的值以验证是否分配了正确的值,并根据inputType的值范围检查typeInput的值。如果输入与预期的相同,则将typeInput分配给customInput.type

memset()的调用将起作用,但是为什么要用位移位来混淆事情呢?这里也不需要&操作符,但在这种情况下,它们是可以的。相反,考虑:

代码语言:javascript
复制
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);

这是修正后的代码。这使用gcc -std=c11 -Wall -Wextra -Wpedantic编译时没有警告。

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

GCC输出警告

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

代码语言:javascript
复制
bad_program.c:27:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         .title = {&customInputTitle[0], &customInputTitle[1]},
                   ^
bad_program.c:27:19: note: (near initialization for ‘customInput.title[0]’)
bad_program.c:27:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         .title = {&customInputTitle[0], &customInputTitle[1]},
                                         ^
bad_program.c:27:41: note: (near initialization for ‘customInput.title[1]’)
bad_program.c:28:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         .extra = {&customInputExtra[0], &customInputExtra[1]},
                   ^
bad_program.c:28:19: note: (near initialization for ‘customInput.extra[0]’)
bad_program.c:28:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         .extra = {&customInputExtra[0], &customInputExtra[1]},
                                         ^
bad_program.c:28:41: note: (near initialization for ‘customInput.extra[1]’)
bad_program.c: In function ‘main’:
bad_program.c:36:5: warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]
     memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
     ^~~~~~
bad_program.c:36:5: warning: incompatible implicit declaration of built-in function ‘memset’
bad_program.c:36:5: note: include ‘<string.h>’ or provide a declaration of ‘memset’
bad_program.c:25:33: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘inputType * {aka enum <anonymous> *}’ [-Wformat=]
 #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                 ^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
     sscanf(payload, CUSTOM_INPUT_REGX,
                     ^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 4 has type ‘unsigned char (*)[40]’ [-Wformat=]
 #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                 ^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
     sscanf(payload, CUSTOM_INPUT_REGX,
                     ^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^=’ expects argument of type ‘char *’, but argument 5 has type ‘unsigned char (*)[40]’ [-Wformat=]
 #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                 ^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
     sscanf(payload, CUSTOM_INPUT_REGX,
                     ^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 6 has type ‘unsigned char (*)[40]’ [-Wformat=]
 #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                 ^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
     sscanf(payload, CUSTOM_INPUT_REGX,
                     ^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%s’ expects argument of type ‘char *’, but argument 7 has type ‘unsigned char (*)[40]’ [-Wformat=]
 #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                 ^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
     sscanf(payload, CUSTOM_INPUT_REGX,
                     ^~~~~~~~~~~~~~~~~
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53850625

复制
相关文章

相似问题

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