我正在尝试使用以下方式解析xxxxxx(xxxxx)
格式字符串:sscanf
sscanf(command, "%s(%s)", part1, part2)
但似乎sscanf
不支持这种格式,因此part1
实际上包含整个字符串。
谁有这方面的经验请分享...
谢谢
将代码转换为程序:
#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
转换说明符会跳过前导空白,然后扫描“非空白”字符直到下一个空白字符(或者,在这种情况下,是字符串的结尾)。
您需要使用(否定的)字符类或扫描集来获得您想要的结果:
#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 是(可选)最大字段宽度的示例。该[...]
部分是一个scansets
,它也许可以被视为转换说明符的一个特例。转换说明%s
符大致等价于%[^ \t\n]
。
31 比字符串的长度小一;最后的 null 不计入该长度。因为part1
andpart2
都是 32 的数组char
,所以%31[^(]
or%31[^)]
转换说明符防止缓冲区溢出。如果第一个字符串在 之前超过 31 个字符(
,您将获得 1 的返回值,因为文字左括号不匹配。同样,第二个字符串将被限制为 31 个字符,但您无法轻易判断 是否)
在正确的位置。
如果您确切知道“命令”的各个部分有多长,那么最简单的选择是:
sscanf(command, "%6s(%5s)", part1, part2);
这假设“part1”始终为 6 个字符,“part2”始终为 5 个字符(如您的代码示例中所示)。
试试这个:
#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!"