从scanf
的man
页面:
指示词是下列其中一项:
- 空白字符序列(空格、制表符、换行符等;这个指令匹配输入中任意数量的白色,包括没有空格。
*一个普通字符(即白色或' %'之外的字符)。此字符必须与输入的下一个字符完全匹配。(着重号是我的) - 一种转换规范,以“%”(百分比)字符开头。根据此规范转换输入的字符序列,并将结果放在相应的指针参数中。如果输入的下一项与转换规范不匹配,则转换失败-这是匹配失败。
下面的代码是:
#include <stdio.h>
int main(void)
{
const char* fmt = "A %49s B";
char buf[50];
printf("%d\n", sscanf("A foo B", fmt, buf)); // 1
printf("%d\n", sscanf("blah blaaah blah", fmt, buf)); // 0
printf("%d\n", sscanf("A blah blah", fmt, buf)); // 1
return 0;
}
第1行和第3行打印1
,因为“A”与“A”匹配成功,“foo”/“blah”与%s
匹配也成功。第2行打印0
,因为“A”不能与“blah”匹配,所以解析在此停止。
这一切都很好,也很符合逻辑,但是在所有转换规范都成功匹配并赋值之后,有没有办法检测到匹配失败?在这种情况下,scanf
返回的值将是我的格式字符串中转换说明符的个数,所以我不能用它来判断匹配是否成功,直到最后。
换句话说就是:第3行中输入sscanf
的字符串不是“valid”,因为它的格式不是A [something] B
。我可以使用scanf
来检测它吗?或者strtok
是我唯一的选择吗?
4条答案
按热度按时间3xiyfsfu1#
在格式末尾使用
" %n"
。指令:
" "
扫描0个或多个空白。不会失败。"%n"
保存到目前为止解析的字符数计数(作为int
)。它不会失败。将
n
设置为0并测试它是否发生了更改。只有在前面的整个格式都成功时才会发生更改。还要测试扫描是否在空字符上结束-从而检测到不需要的尾随文本。添加的
" "
,虽然是可选的,但如果作为一个典型的尾随空格(通常是'\n'
)非常有用的话,它并不具有攻击性。它否定了对扫描的文本行进行预处理以删除其行尾的需要。输出量
请注意,成功与否仅由
n
决定。如果未成功,则不应使用目标扫描变量(如buf
)。如果需要部分结果,则使用返回值sscanf()
。kfgdxczn2#
如果你想解析更复杂的输入,使用一个合适的解析器/lexxer,否则,看看
%n
转换说明符:不使用任何输入。相应的参数应该是一个指向有符号整数的指针,该整数将被写入到此fscanf函数调用到目前为止从输入流中读取的字符数。执行%n指令不会增加fscanf函数执行完成时返回的赋值计数。不转换任何参数,但有一个被消耗了。2如果转换说明中包含赋值禁止字符或字段宽度,则该行为未定义。
您可以多次使用此选项:在最后一个变量转换之后和最后一个变量转换之后。
jk9hmnmh3#
对于OP的用例,同样可以使用
regex
来匹配模式。cgh8pdjw4#
如果您只对是否已扫描整个格式感兴趣,而不关心流中的尾随文本,则可以使用以下简洁的方法:
技巧是,除非整个格式都匹配成功,否则
"%n"
转换不会发生。由于格式的任何匹配都将消耗流中的一个或多个字符,因此"%n"
写入的值将始终为非零值。因此,当且仅当整个格式都匹配时,success
才会被设置为真实值。