我遇到了一些代码,并想知道最初的开发人员是做什么的。以下是使用此模式的简化程序:
#include <stdio.h>
int main() {
char title[80] = "mytitle";
char title2[80] = "mayataiatale";
char mystring[80];
/* hugh ? */
sscanf(title,"%[^a]",mystring);
printf("%s\n",mystring); /* Output is "mytitle" */
/* hugh ? */
sscanf(title2,"%[^a]",mystring); /* Output is "m" */
printf("%s\n",mystring);
return 0;
}
man page for scanf有相关信息,但我无法阅读它。使用这种表示法的目的是什么?它想要完成什么?
字符类的主要原因是%s符号在第一个空白字符处停止,即使您指定字段长度,并且您经常不希望它。在这种情况下,字符类表示法可能非常有用。
考虑这段代码来读取最多10个字符的行,丢弃任何多余的字符,但保留空格:
#include <ctype.h>
#include <stdio.h>
int main(void)
{
char buffer[10+1] = "";
int rc;
while ((rc = scanf("%10[^\n]%*[^\n]", buffer)) >= 0)
{
int c = getchar();
printf("rc = %d\n", rc);
if (rc >= 0)
printf("buffer = <<%s>>\n", buffer);
buffer[0] = '\0';
}
printf("rc = %d\n", rc);
return(0);
}
这实际上是关于getline()
变体的comp.lang.c.moderated(大约2004年6月)讨论的示例代码。
至少有一些混乱。第一个格式说明符%10[^\n]
最多可读取10个非换行符,并将它们分配给缓冲区以及尾随空值。第二个格式说明符%*[^\n]
包含赋值抑制字符(*
),并从输入中读取零个或多个剩余的非换行符。当scanf()
函数完成时,输入指向下一个换行符。循环体读取并打印该字符,这样当循环重新开始时,输入正在查看下一行的开头。然后重复该过程。如果该行短于10个字符,则将这些字符复制到缓冲区,并且“零或多个非换行”格式处理零非换行。
像%[a]
和%[^a]
这样的结构存在,因此scanf()
可以用作一种词法分析器。这有点像%s
,但它们不是收集尽可能多的“字符串”字符的范围,而是收集字符类所描述的字符范围。可能有些情况下写%[a-zA-Z0-9]
可能有意义,但我不确定我看到一个令人信服的用例与scanf()
补充类。
恕我直言,scanf()
根本不适合这项工作。每当我开始使用其中一个更强大的功能时,我最终都会将其剥离并以不同的方式实现该功能。在某些情况下,这意味着使用lex编写一个真正的词法分析器,但通常在I / O时进行行并在进行值转换之前将其粗略地分解为使用strtok()
的标记就足够了。
编辑:我通常因为面对坚持提供错误输入的用户而扯掉scanf()
,它只是不善于帮助程序提供有关问题的良好反馈,并且有一个汇编程序打印“错误,终止”。因为它唯一有用的错误消息与我的用户不太好。 (在这种情况下,我。)
这就像正则表达式中的字符集; [0-9]
匹配一串数字,[^aeiou]
匹配任何非小写元音等。
有各种各样的用途,例如拔出数字,标识符,空格块等。
您可以在线查看ISO/IEC9899 standard中的相关内容。
以下是我从[
(页286)文档中引用的一段:
匹配一组预期字符的非空字符序列。
转换说明符包括格式字符串中的所有后续字符,包括匹配的右括号(])。括号(扫描列表)之间的字符组成扫描集,除非左括号后面的字符是抑扬符(^),在这种情况下,扫描集包含在旋转和右括号之间的扫描列表中不出现的所有字符。如果转换说明符以[]或[^]开头,则右括号字符位于扫描列表中,下一个右括号字符是结束规范的匹配右括号;否则第一个右括号字符是结束规范的字符。如果 - 字符在扫描列表中并且不是第一个字符,也不是第一个字符是^的第二个字符,也不是最后一个字符,则行为是实现定义的。