sscanf和换行符

10

我需要解析类似以下服务器响应的内容:

risposta:

200\n
Len 1040\n
Expire 30\n
\n
1111111111111111111111111\n
1111111111111111111111111\n
1111111111111111111111111\n

我正在尝试使用sscanf:

sscanf(risposta, "%d\nLen %d\nExpire %d\n\n%s[^\0]", &risp->type, &risp->len, &risp->expire, risp->risorsa);

但它只将1111111111111111111111111放入risp->risorsa中。如何解决?

附:结构体risp:

typedef struct Server_risp {
   int type;
   int expire;
   int len;
   int sup;
   int inf;
   char risorsa[5000];
 }Server_risp;
3个回答

7
一个扫描集规范不是%s[whatever],而只是%[whatever],所以你的格式字符串应该更像:"%d\nLen %d\nExpire %d\n\n%[^\0]"
另外,scanf和相关函数认为格式字符串中的任何空格都等同于其他任何空格——格式中的任何空格都匹配输入中的任意序列的空格字符(换行符被视为空格)。你当前的格式字符串很好地记录了你期望的格式,但从实际匹配的角度来看,你可以将其更改为类似于:"%d Len %d Expire %d %[^\0]",而不会影响它的功能。特别是,你连续的两个换行符并没有真正发挥作用。
编辑:思考一下,[\0]会引起一些问题:"\0"终止了字符串,因此你最终得到了一个无效的扫描集规范。由于你只想让剩余的输入进入risorsa,所以最简单的方法可能是使用%c"%d Len %d Expire %d %4999c"
是的,这次我实际测试了它。
#include <stdio.h>

char *riposta = "200\n"
    "Len 1040\nExpire 30\n"
    "\n1111111111111111111111111\n"
    "1111111111111111111111111\n"
    "1111111111111111111111111\n";

typedef struct Server_risp {
    int type;
    int expire;
    int len;
    int sup;
    int inf;
    char risorsa[5000];
}Server_risp;

int main() {
    Server_risp risp;
   sscanf(riposta, "%d Len %d Expire %d %4999c", &risp.type, &risp.len, &risp.expire, risp.risorsa);

   printf("%s\n", risp.risorsa);
}

结果:

1111111111111111111111111
1111111111111111111111111
1111111111111111111111111

编辑2:我不确定你在这里遇到了什么问题。我稍微修改了一下,以显示前导和嵌入式空格的读取:

#include <stdio.h>

char *riposta = "200\n"
"Len 1040\nExpire 30\n"
"|        |"
"\n1111111111111111111111111\n"
"1111111111111111111111111\n"
"1111111111111111111111111\n";

typedef struct Server_risp {
    int type;
    int expire;
    int len;
    int sup;
    int inf;
    char risorsa[5000];
}Server_risp;

int main() {
    Server_risp risp;
    sscanf(riposta, "%d Len %d Expire %d%4999c", &risp.type, &risp.len, &risp.expire, risp.risorsa);

    printf("%s\n", risp.risorsa);
}

我运行了代码并得到了预期的结果:

|        |
1111111111111111111111111
1111111111111111111111111
1111111111111111111111111

我尝试使用%[^\0],但它没有将任何内容放入risp->risorsa中,也没有放入第一行。 - Gorgo
尝试过使用%[^\a],它能工作..但我需要解析直到EOF的所有内容。 \0有什么问题吗?实际上gcc会显示以下信息: parser.c:163: 警告: 格式中没有闭合‘]’ parser.c:163: 警告:格式中嵌入了‘\0’ - Gorgo
新问题相关内容如下: %4999c解决方案中,响应以空格开头,例如:char *riposta = "200\n" "Len 1040\nExpire 30\n" "__________1111111111111111111111111\n" "1111111111111111111111111\n" "1111111111111111111111111\n";risp->risorsa需要是 __________1111111111111111111111111 1111111111111111111111111 1111111111111111111111111非常重要:我使用_来模拟“ ”。 - Gorgo
如果您需要保留前导空格,请删除 %c 前面的空格,这样就像 "%d Len %d Expire %d%4999c"。 - Jerry Coffin
好的Jerry,现在它可以工作了:D。我添加了以下内容: for (i=0; i<strlen(risp_aux->risorsa); i++){ p_aux = &risp_aux->risorsa[2+i]; risp_aux->risorsa[i]=*(p_aux); } 以删除开头的\n\n。 - Gorgo

0

我想指出一个解决以下问题的方法:

sscanf(risposta, "%d\nLen %d\nExpire %d\n\n%s[^\0]", &risp->type, &risp->len, &risp->expire, risp->risorsa);

代码中的问题是在闭合方括号“]”之前'\0'终止了字符串。您可以使用'\1'。这样,字符串就不会过早地终止,sscanf将继续扫描直到扫描完整个字符串。

更正后的代码如下:

sscanf(risposta, "%d\nLen %d\nExpire %d\n\n%s[^\1]", &risp->type, &risp->len, &risp->expire, risp->risorsa);

也许这正是你一开始想要做的。


-2

以下代码存在一些问题:

sscanf(risposta, "%d\nLen %d\nExpire %d\n\n%s[^\0]", &risp->type, &risp->len, &risp->expire, risp->risorsa);

应该是:

char tmp_str[100]; 

sscanf(risposta, "%d %s %d %s %d %s[^\0]", &risp->type, tmp_str, &risp->len, tmp_str, &risp->expire, risp->risorsa);

你需要处理字符串 "Len" 和 "Expire",而且 sscanf 无法处理它们。


抱歉给你点踩,但你提供的建议是错误的,并且你没有解决真正的问题。 - Jerry Coffin
我不需要处理“Len”或“Expire”,只需要它们的整数。 然而,%s[^\0] 只输出第一行: printf("%s%d\n%d\n%d\n%s\n%s",ORANGE,risp->type,risp->len,risp->expire,risp->risorsa,WHITE);200 1040 30 1111111111111111111111111 - Gorgo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接