正如BLUEPIXY 在comment 中所说,一个问题是“你有足够的空间来存储字符串吗?”确实,您的变量是char string1[SOME_SIZE]; 还是char *string1;,如果是后者,您如何为它们分配空间?奇怪的多余字符等症状通常是由于正在读取的数据空间不足造成的。
您可以将这两个操作合并为一个。您还应该限制阅读的大小;你应该检查你的阅读是否成功。假设你有两个大小为 128 的数组,你可以写
char string1[128];
char string2[128];
if (sscanf(buffer, "%127s \"%127[^\"]\"", string1, string2) != 2)
…format error…
注意,格式字符串中指定的数字是字符串的最大长度不包括空字节。这与库的其他部分并不完全一致,但早在 C 标准出现之前就已建立实践,并且更改规则所破坏的内容比修复的要多。
还要注意,使用上面的代码,您永远不会知道尾随双引号是否存在。如果您也需要这些信息,则必须更加努力:
int offset = 0;
char string1[128];
char string2[128];
if (sscanf(buffer, "%127s \"%127[^\"]\"%n", string1, string2, &offset) != 2 || offset == 0)
…format error…
最后,如果您在 POSIX 系统上,%s 和 %c 和 %[…] 操作的 m 修饰符会动态地为读取的数据分配正确的空间量(但您通过指向 char * 的指针,以供转换规范使用,而不是普通的 char *):
int offset = 0;
char *tag = 0;
char *value = 0;
if (sscanf(buffer, "%ms \"%m[^\"]\"%n", &tag, &value, &offset) != 2 || offset == 0)
…format error…
请注意,某些系统(例如 Mac OS X 10.10.1 Yosemite)不支持 m 修饰符,即使它是 sscanf() 的 POSIX 2008 规范的一部分。 GNU C 库(例如在 Linux 上找到)确实支持它。
值得思考sscanf() 是否是处理这些数据的最佳方式。可以使用它:我刚刚展示了如何使用(当你写这个问题时,你已经拥有了大部分你需要的东西)。然而,准确使用它是一个棘手的功能——这就是礼貌。 sscanf() 的好处在于,您可以实现“如果一开始没有成功,请尝试、尝试、再试”。使用像scanf() 这样的直接I/O 功能,一般情况下您不能再试一次。但是,您也可以使用字符串操作来获得您想要的输出,尽管这样做的简单方法会破坏输入字符串:
char *tag = buffer + strspn(buffer, " \t"); // Skip leading blanks and tabs
char *eot = tag + strcspn(tag, " \t"); // Tag does not contain blanks or tabs
if (*eot == '\0')
…report format error (no value after tag); do not continue…
*eot++ = '\0'; // Null terminate the tag
char *value = eot + strspn(eot, " \t"); // Skip separating blanks and tabs
if (*value++ != '"')
…report format error (missing open double quote); do not continue…
char *eov = strchr(value, '"');
if (eov == 0)
…report format error (missing close double quote); do not continue…
*eov = '\0';
还有其他方法可以进行该扫描,但 strspn() 和 strcspn() 是 C89 和所有更高版本的标准中的标准函数。
工作测试代码
使用 GCC 4.8.2 在 Ubuntu 14.04 LTS 上测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void parsing(char *buffer)
{
char *tag = buffer + strspn(buffer, " \t"); // Skip leading blanks and tabs
char *eot = tag + strcspn(tag, " \t"); // Tag does not contain blanks or tabs
if (*eot == '\0')
{
printf("Got tag <<%s>> but no following data\n", tag);
return;
}
*eot++ = '\0'; // Null terminate the tag
char *value = eot + strspn(eot, " \t"); // Skip separating blanks and tabs
if (*value++ != '"')
{
printf("Got tag <<%s>> but it is not followed by a double-quoted string\n", tag);
return;
}
char *eov = strchr(value, '"');
if (eov == 0)
{
printf("Got tag <<%s>> and value <<%s>> but it is not followed by a double-quote\n", tag, value);
return;
}
*eov = '\0';
printf("<<%s>> <<%s>>\n", tag, value);
}
int main(void)
{
char buffer[] = " \ttagname \" corresponding tag \tvalue is OK \" ";
{
int offset = 0;
char string1[128];
char string2[128];
if (sscanf(buffer, "%127s \"%127[^\"]\"%n", string1, string2, &offset) != 2 || offset == 0)
printf("sscanf() 1 failed\n");
else
printf("<<%s>> <<%s>>\n", string1, string2);
}
{
int offset = 0;
char *tag = 0;
char *value = 0;
if (sscanf(buffer, "%ms \"%m[^\"]\"%n", &tag, &value, &offset) != 2 || offset == 0)
printf("sscanf() 2 failed\n");
else
printf("<<%s>> <<%s>>\n", tag, value);
free(tag);
free(value);
}
parsing(buffer);
return 0;
}
输出:
<<tagname>> << corresponding tag value is OK >>
<<tagname>> << corresponding tag value is OK >>
<<tagname>> << corresponding tag value is OK >>