如何在获得新输入之前清除stdin?

我已经阅读了大约5-10个不同的建议如何清除标准输入,但它们都不适合我的需要。 问题是fflush(stdin)在我的计算机上工作得很好,但不幸的是它似乎无处不在,所以我需要具有相同function的东西。 我尝试的每一种方式都清除了stdin,当它不是空的时候需要用户输入当stdin是空的时候,这意味着它需要输入片刻我不想得到任何东西(+它无论如何丢弃它)。

问题是:在我需要用户输入之前,我可以以某种方式确定stdin是空的吗? (如果没有,那么,然后才以某种方式清除它?)类似于:

 if (stdin is NOT empty) while (getchar() != '\n') continue; 

编辑:问题是我从stdin逐个加载字符,在某些时候,上一次迭代的输入的一部分可能会或可能不会被丢弃。 无论哪种方式,在我要求用户处理另一个输入之前,我需要有明确的stdin输入。 清除缓冲区本身并不是一件大事,问题是当程序到达清除stdin点时输入为空时会发生什么,因为在那一刻程序需要另一个输入,它将被清除吃掉function。 这就是我想要摆脱的东西。 (当我可以使用fflush(stdin);我只知道,对于我的程序的下一行, stdin将是空的,无论如何,没有问题……)

如何在获得新输入之前清除stdin?
..所以我需要具有相同function的东西。

使用便携式C,这是不可能的。


而是建议一个不同的(和更常见的C)范例:确保以前的输入函数消耗所有先前的输入。

fgets() (或* nix getline() )是典型的方法,可以解决大多数情况。

或者自己滚动。 以下消耗,但不保存额外的输入。

 int mygetline(char *buf, size_t size) { assert(size > 0 && size < INT_MAX); size_t i = 0; int ch; while ((ch = fgetc(stdin)) != EOF) { if (i + 1 < size) { buf[i++] = ch; } if (ch == '\n') { break; } } buf[i] = '\0'; if (i == 0) { return EOF; } return i; } 

TL; DR fflush(stdin)按照标准调用未定义的行为 ,你永远不应该使用它。


来到你的代码(逻辑),而不是寻找换行符,你可以寻找EOF 。 它没有先决条件, stdin在运行此循环之前应该有一些输入。

就像是

  while (getchar() != EOF); //; is not a mistake 

应该满足你的需求。

使用fgets()来读取stdin

使用足够大的缓冲区和/或测试整行。

使用fgets()您永远不必担心stdin额外字符。

 // read characters until 'X' while (((ch = getchar()) != EOF) && (ch != 'X')) putchar(ch); // discard X and the rest of the line fflush(stdin); // UB except for Windows 

 // read full line char tmp[1000], *p; if (!fgets(tmp, sizeof tmp, stdin)) /* deal with error */; if (!*tmp) /* embedded NUL detected: input is not a text file */; if (tmp[strlen(tmp) - 1] != '\n') /* partial line */; p = tmp; while (*p && *p != 'X') putchar(*p++); // ignore the X and all the subsequent characters 

select模块提供了一个名为select的function,可以实现您正在寻找的function。 select.select有三个参数:

 select.select(rlist, wlist, xlist) 

每个参数都应该是文件描述符列表(例如[sys.sdtin] ),然后等待特定的IO操作可用。 IO操作在给定文件描述符上是rad,wite或其他一些操作。 它返回一个对应列表的tuple ,这些列表填充了准备好的文件描述符。

所以,如果在sys.stdin有输入等待,那么该函数将表现如下:

 >>> import select >>> import sys >>> >>> select.select([sys.stdin], [], []) ([sys.stdin], [], []) >>> 

就其本身而言,这并不能解决您的问题,因为默认情况下,该function将一直等到IO操作可用。 但重要的是, select.select有一个可选的timeout参数,表示在放弃之前等待多长时间。 我们只需要将超时设置为零,我们可以在不阻止程序流的情况下检查输入。

让我们看一个sys.stdin没有输入等待的sys.stdin

 >>> import select >>> import sys >>> >>> timeout = 0 >>> select.select([sys.stdin], [], [], timeout) ([], [], []) >>> 

知道我们只想要那个元组的第一个元素(输入流),我们已经准备好做一个有用的if语句:

 if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: print('Input is waiting to be read.') 

这意味着清除输入流只需要一些迭代:

 while sys.stdin in select.select([sys.stdin], [], [], 0)[0]: sys.stdin.readline() 

我们当然可以在任何输入流上使用它,所以我们把它放在一个函数中:

 def clear_input(stream, timeout=0): '''Takes an input stream and discards each line in the buffer. The given timeout denotes how long in seconds to wait for further input when none is available. ''' while stream in select.select([stream], [], [], timeout)[0]: stream.readline() 

因此,让我们展示我们的function,以实现您在问题中所要求的内容:

 import select import sys import time def clear_input(stream, timeout=0): while stream in select.select([stream], [], [], timeout)[0]: stream.readline() if __name__ == '__main__': print('Type some lines now. They will be ignored.') time.sleep(5) print('Clearing input.') clear_input(sys.stdin) user_input = raw_input('Please give some fresh input: ') print(user_input) 

clear_input函数可以用作清除输入流的非阻塞方式,并且应该在Python2和Python3中工作。