我正在尝试使用xxxxxx(xxxxx)
解析sscanf
格式字符串,如下所示:
sscanf(command, "%s(%s)", part1, part2)
但似乎sscanf
不支持此格式,因此part1
实际上包含整个字符串。
任何人都有这方面的经验请分享......
谢谢
答案 0 :(得分:7)
将代码转换为程序:
#include <stdio.h>
int main(void)
{
char part1[32];
char part2[32];
char command[32] = "xxxxx(yyyy)";
int n;
if ((n = sscanf(command, "%s(%s)", part1, part2)) != 2)
printf("Problem! n = %d\n", n);
else
printf("Part1 = <<%s>>; Part2 = <<%s>>\n", part1, part2);
return 0;
}
运行时会生成“Problem! n = 1
”。
这是因为第一个%s
转换说明符会跳过前导空格,然后扫描“非空白”字符,直到下一个空格字符(或者,在本例中为字符串结尾)。 / p>
您需要使用(否定的)字符类或 scansets 来获得所需的结果:
#include <stdio.h>
int main(void)
{
char part1[32];
char part2[32];
char command[32] = "xxxxx(yyyy)";
int n;
if ((n = sscanf(command, "%31[^(](%31[^)])", part1, part2)) != 2)
printf("Problem! n = %d\n", n);
else
printf("Part1 = <<%s>>; Part2 = <<%s>>\n", part1, part2);
return 0;
}
这会产生:
Part1 = <<xxxxx>>; Part2 = <<yyyy>>
注意31的格式;它们可以防止溢出。
我想知道%31是如何运作的。它是否以
%s
的形式工作并防止溢出或仅防止溢出?
使用给定的数据,这两行是等效的,并且足够安全:
if ((n = sscanf(command, "%31[^(](%31[^)])", part1, part2)) != 2)
if ((n = sscanf(command, "%[^(](%[^)])", part1, part2)) != 2)
%[...]
表示法是转换规范; %31[...]
也是如此。
C标准说:
每个转换规范都由字符%引入。 在%之后,以下顺序出现:
- 可选的赋值抑制字符*。
- 大于零的可选十进制整数,指定最大字段宽度 (字符)。
- 可选的长度修饰符,用于指定接收对象的大小。
- 转换说明符字符,指定要应用的转换类型。
31是(可选)最大字段宽度的示例。 [...]
部分是 scanset ,它可能被视为s
转换说明符的特例。 %s
转化说明符大致相当于%[^ \t\n]
。
31比字符串的长度少一个;最后的空值不计入该长度。由于part1
和part2
均为32 char
的数组,因此%31[^(]
或%31[^)]
转换说明符可防止缓冲区溢出。如果第一个字符串在(
之前超过31个字符,则由于文字左括号不匹配,因此返回值为1。同样,第二个字符串将限制为31个字符,但您无法轻易判断)
是否在正确的位置。
答案 1 :(得分:2)
如果您确切知道“命令”的各个部分有多长,那么最简单的选项是:
sscanf(command, "%6s(%5s)", part1, part2);
这假定'part1'总是6个字符长,'part2'总是5个字符长(如代码示例中所示)。
答案 2 :(得分:1)
请改为尝试:
#include <stdio.h>
int main(void)
{
char str1[20];
char str2[20];
sscanf("Hello(World!)", "%[^(](%[^)])", str1, str2);
printf("str1=\"%s\", str2=\"%s\"\n", str1, str2);
return 0;
}
输出(ideone):
str1="Hello", str2="World!"