为什么scanf()转换实际上有效?

时间:2016-04-08 03:15:56

标签: c scanf

啊,这是一个程序员逐渐编写一些代码的古老故事,他们不希望做任何超出预期的事情,但代码意外地做了所有事情,也正确地做了。

我正在研究一些C编程实践问题,其中一个是将stdin重定向到包含一些代码行的文本文件,然后使用scanf()和printf()将其打印到控制台。我也无法将换行字符打印出来(因为scanf通常会占用空白字符)并且在我决定重新开始并输入以下内容时输入了涉及多个条件和标志的混乱代码:

(其中c是一个足以容纳整个文本文件内容的字符缓冲区)

scanf("%[a-zA-Z -[\n]]", c);
printf("%s", c);

而且,瞧,这完美无缺。我试图通过在字符类(外部括号之间)上创建变体来找出原因,例如:

[\w\W -[\n]]
[\w\d -[\n]]
[. -[\n]]
[.* -[\n]]
[^\n]

但这些都没有奏效。他们最终只读了一个字符或者产生了乱七八糟的随机字符。 '[^ \ n]'不起作用,因为文本文件包含换行符,因此它只打印出一行。

由于我还没弄明白,我希望那里有人知道这两个问题的答案:

  • 为什么“[a-zA-Z - [\ nn]]”按预期工作?
  • 文本文件包含字母,数字和符号(':',' - ','>',可能包含其他一些内容);如果'a-z'应该表示“所有字符从unicode'a'到unicode'z'”,那么'a-zA-Z'如何包含数字?
  • 似乎你可以在括号内输入的语法很像正则表达式(我对Python很熟悉),但不完全正确。我已经阅读了试图找出这个问题可以使用的内容,但是我无法找到任何信息来比较这种语法与正则表达式的对比。那么:他们是如何相似和不同的?

我知道这可能不是scanf的一个很好的用法,但由于它来自练习题,因此必须暂时忽略真实世界约定。

谢谢!

2 个答案:

答案 0 :(得分:3)

你正在拿起号码,因为你有" - ["在你的角色集中。这意味着从空格(32)到开括号(91)的所有字符,其中包括ASCII(48-57)中的数字。

你的其他例子也包括这一点,但他们缺少" a-zA-Z",它可以让你拿起小写字母(97-122)。序列如' \ w'被视为字符串本身中的未知转义序列,因此\w只是一个w。字面意思是.*。他们没有像正则表达式那样具有特殊意义。

答案 1 :(得分:0)

如果在-中包含[(开头或结尾除外),则行为为实现定义

这意味着您的编译器文档必须描述行为,因此您应该参考该文档以查看定义的行为是什么,这可以解释为什么您的某些代码有效,而有些代码没有。

如果您想编写可移植代码,那么除了匹配连字符之外,您不能将-用作其他任何内容。