【问题标题】:ANSI C - how to read from stdin word by word?ANSI C - 如何逐字读取标准输入?
【发布时间】:2012-04-13 20:54:15
【问题描述】:

代码:

#include <stdio.h>
int main(void) {
    char i[50];
    while(scanf("%s ", i)){
        printf("You've written: %s \n", i);
    }
    printf("you have finished writing\n");

    return 0;
}

一个问题是代码没有按预期执行。如果我输入:

abc def ghi.

它会输出:

You've written: abc
You've written: def

我该如何解决?目标是从标准输入读取每个单词,直到它到达“ENTER”或“。” (点)。

【问题讨论】:

  • 写一次scanf("%s"),然后在循环中调用scanf(" %s")怎么样?
  • 抛开问题不谈,在这种情况下请使用scanf("%49s ", i),以养成防止缓冲区溢出的习惯。 'K?
  • 谢谢,但他们没有解决问题。问题是 while 循环在到达最后一组字符之前结束,这不是它应该做的。

标签: c


【解决方案1】:

@cnicutar 非常接近,但是您显然只想从空白以外的地方开始阅读,并且想在到达空白时停止阅读单个单词,因此对于您的扫描集,您可能想要更多类似的东西:

while(scanf(" %49[^ \t.\n]%*c", i)) {

在这种情况下,初始空格会跳过任何前导空格。然后扫描集读取直到它到达空格、制表符、换行符或句点。然后 %*c 读取(但丢弃)下一个字符(通常是停止扫描的那个)。

但是,当/如果您到达缓冲区的末尾时,这可能会丢弃一个字符,因此您可能想要使用 %c,并提供一个要读入的字符。这将使您从一个比您提供的缓冲区更长的单词中恢复。

【讨论】:

    【解决方案2】:

    怎么样:

    scanf("%49[ ^\n.]", str)
    

    或者类似的东西。

    【讨论】:

    • 这实际上不会在 空格 上中断,是吗?
    • 仅供参考... "%49[^\n.]" 是什么意思?是一些正则表达式模式还是类似的东西?谢谢!
    • @dmckee 它没有。我的印象是操作员想要阅读整行。 Jerry Coffin 有一个更好的答案。
    • @nay:都在man page 中。不是正则表达式,而是字符类。
    【解决方案3】:

    完全抛弃scanf,改用fgets

    while (fgets(i, sizeof i, stdin))
    {
      printf("you've written: %s\n", i);
    }
    

    有以下注意事项:

    1. 如果目标缓冲区中有空间,fgets 会将尾随换行符存储为输入的一部分;

    2. 如果您想在找到 . 时停止阅读,则必须添加一些逻辑以在输入字符串中查找它,例如:

    
        int foundDot = 0;
        while (fgets(i, sizeof i, stdin) && !foundDot)
        { 
          char *dot = strchr(i, '.');
          char *newline = strchr(i, '\n');
    
          if (dot != NULL)
          {
            foundDot = 1;
            *dot = 0; // overwrite the '.' character with the 0 terminator
          }
    
          if (newline != NULL)
          {
            *newline = 0; // overwrite newline character with 0 terminator
          }
    
          /**
           * Assuming you don't want to print a blank line if you find a dot
           * all by itself. 
           */
          if (strlen(i) > 0) 
            printf("you've written: %s\n", i);
        }

    【讨论】:

      【解决方案4】:

      最简单的方法是使用flex。否则你会重复一堆困难、复杂的工作,而且很可能会犯错误。

      另外,请阅读lex and yacc, 2nd edition

      【讨论】:

      • 可能吗?当然。最简单?也许不是。
      • 对于这个特殊的问题,这有点像用手提钻挂画钩。
      • @JohnBode 也许吧,但我发现所有其他“简单”解决方案最终都变得工作量更大、效率更低,并且充满了细微的错误。主要是因为问题很快就超出了玩具/琐碎的初始问题集。
      猜你喜欢
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 2021-06-18
      • 2018-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多