sscanf返回1读取字符串

时间:2018-09-13 09:06:29

标签: c

返回一个是什么意思?

谁能帮助我找到我的问题所在?

char* line = "\"ThisId\":\"\"";
char key[32], value[512];
if (sscanf(line, "\"%31[^\"]\":\"%511[^\"]\"", key, value) != 2) {
    return false;
}

我想读取密钥= ThisId

在这种情况下,值应该为空。

看起来密钥正在获取整个字符串,因此值不会得到任何值。

3 个答案:

答案 0 :(得分:2)

原因是格式说明符[...]与空输入不匹配。例如,在链接的C标准草案中赋予conversion specifiers的含义,并注意“非空”(强调是我的):

  

[...匹配一组预期字符(扫描集)中的非空字符序列

因此,“空”值(即两个\"之间没有任何字符的输入)将根本不匹配格式,这就是scanf的结果不是2的原因在这种情况下。

无论如何,scanf具有多种输入格式和介于两者之间的字符通常变得非常棘手且容易出错。我建议读完整的一行,例如使用fgets,然后解析它,例如使用strtokstrchr。由于您已经有了一行,因此,您当然会跳过fgets-事情。

答案 1 :(得分:2)

  

我的问题在哪里?

当说明符不匹配任何内容时,对sscanf()所做的操作的预期不正确。


char* line = "\"ThisId\":\"\"";
char key[32], value[512];
if (sscanf(line, "\"%31[^\"]\":\"%511[^\"]\"", key, value) != 2) {

由于line"%511[^\"]"不匹配,因此扫描停止。在这种情况下,value[]保持不变,并且scanf()报告成功扫描1的指定符数量。


另一个问题退出了。

在下面使用line2的情况下,sscanf()将用value[]填充"xyz",而sscanf()将按预期返回2。

char* line2 = "\"ThisId\":\"xyz\"";

在下面的line3中,sscanf()会用value[]填充"xyz",并且sscanf()返回2,即使line3没有最后一个'\"'

char* line3 = "\"ThisId\":\"xyz";

使用下面的line4sscanf()将用value[]填充"xyz",而sscanf()返回2,即使line4在最后'\"'

char* line4 = "\"ThisId\":\"xyz\"blah";

OP的目标是匹配2种不同的sscanf格式之一。我发现使用字符串文字串联可以使代码更易于理解和维护。

#define KEY_FMT "\"%31[^\"]\"
#define SEP_FMT ":"
#define VAL_FMT "\"%511[^\"]\"
#define EMPTY_FMT "\"\"

KEY_FMT SEP_FMT VAL_FMT      /* key and value */
KEY_FMT SEP_FMT EMPTY_FMT    /* key and empty value */

一个简单的解决方案是扫描字符串两次,然后测试扫描是否结束。代码可以用最后一个"%n"进行测试,以记录到目前为止扫描到的字符数如果扫描到达该点

#define N_FMT "%n"

int n = 0;
sscanf(line, KEY_FMT SEP_FMT VAL_FMT N_FMT, key, value, &n);
if (n > 0 && line[n] == '\0') {
  return true; // Found key and value
}

n = 0;
sscanf(line, KEY_FMT SEP_FMT EMPTY_FMT N_FMT, key, &n);
if (n > 0 && line[n] == '\0') {
  value[0] = '\0';
  return true; // Found key and empty value
}

return false;

一个有用的变化是扫描零件

int n = 0;
sscanf(line, KEY_FMT SEP_FMT N_FMT, key, &n);
if (n == 0) {
  return false; // Key or separator not found
}
line += n; // advance

n = 0;
sscanf(line, VALUE_FMT N_FMT, &n);
if (n > 0 && line[n] == '\0') {
  return true; // Found value
}

n = 0;
sscanf(line, EMPTY_FMT N_FMT, value, &n);
if (n > 0 && line[n] == '\0') {
  value[0] = '\0'; 
  return true; // Found empty value
}

return false;

最后,考虑在扫描的各个部分允许空白。

#define KEY_FMT " \"%31[^\"]\"
#define SEP_FMT " :"
#define VAL_FMT " \"%511[^\"]\"
#define EMPTY_FMT " \"\"  
#define N_FMT " %n"

答案 2 :(得分:0)

这是因为[^\"]会读取字符直到到达\"。由于您的输入"\"ThisId\":\"\"";不包含第二个字符串的任何额外字符。  sscanf没有为value读任何东西。

如果要读取空值,请在输入中输入' ',如下所示:

char* line = "\"ThisId\":\" \"";