我已经阅读了大约5-10个不同的建议如何清除标准输入,但它们都不适合我的需要。问题是fflush(stdin)
在我的计算机上工作得很好,但不幸的是它似乎无处不在,所以我需要具有相同功能的东西。我尝试的其他方式清除stdin时,它不是空的,但是当stdin为空时需要用户输入,这意味着它需要输入片刻我不想得到任何东西(+无论如何都丢弃它)。
问题是:在我需要用户输入之前,我可以以某种方式确定stdin
是空的吗? (如果没有,那么,然后才以某种方式清除它?)
类似的东西:
if (stdin is NOT empty)
while (getchar() != '\n')
continue;
编辑:问题是我从stdin
逐个加载字符,在某些时候,上一次迭代的输入的一部分可能会或可能不会被丢弃。在我要求用户处理另一个输入之前,我需要清除stdin
。清除缓冲区本身并不是一件大事,问题是当程序到达清除stdin
时输入为空时会发生什么,因为在那一刻程序需要另一个输入,这将是被清算功能吃掉了。这就是我想要摆脱的东西。 (当我可以使用fflush(stdin);
时,我才知道,对于我的程序的下一行,stdin
无论如何都是空的,没有问题......)
答案 0 :(得分:4)
如何在获得新输入之前清除标准输入? ..所以我需要具有相同功能的东西。
使用便携式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) { // Read until EOF ...
if (i + 1 < size) {
buf[i++] = ch;
}
if (ch == '\n') { // ... or end of line
break;
}
}
buf[i] = '\0';
if (i == 0) {
return EOF;
}
return i;
}
答案 1 :(得分:1)
TL; DR fflush(stdin)
根据标准调用undefined behavior,您绝不应该使用它。
来到您的代码(逻辑),而不是寻找换行符,您可以查找EOF
。在运行此循环之前,它没有stdin
应该某些输入的先决条件。
像
这样的东西 while (getchar() != EOF); //; is not a mistake
应该满足您的需求。
答案 2 :(得分:0)
仅使用 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
答案 3 :(得分:0)
从 similar question,使用 poll(),fds.fd 设置为 0 (stdin),fds.events 设置为 POLLIN,nfds 设置为 1,超时设置为零。调用 poll() 后,如果缓冲区为空,fds.revents 将设置为零,否则设置为 POLLIN。
struct pollfd fds = {0, POLLIN, 0};
poll(&fds, 1, 0);
if(fds.revents == POLLIN}
printf("stdin buffer is not empty");
此解决方案适用于兼容 posix 的系统,但不适用于 Windows。使用 select() 实现便携性。
答案 4 :(得分:-2)
select
模块提供了一个名为select
的功能,可以实现您正在寻找的功能。 select.select
有三个参数:
select.select(rlist, wlist, xlist)
每个参数都应该是文件描述符列表(例如[sys.sdtin]
),然后等待特定的IO操作可用。在给定的文件描述符上,IO操作是 r ead, w rite或其他一些e x ception。它返回填充了准备好的文件描述符的相应列表的tuple
。
因此,如果在sys.stdin
中有输入等待,那么该函数将表现如下:
>>> import select
>>> import sys
>>>
>>> select.select([sys.stdin], [], [])
([sys.stdin], [], [])
>>>
这本身并不能解决您的问题,因为默认情况下该功能将一直等到IO操作可用。但重要的是,select.select
有一个可选的timeout
参数,表示在放弃之前等待多长时间。我们只需要将超时设置为零,我们就可以在不阻止程序流的情况下检查输入。
让我们看一下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()
因此,让我们展示我们在您的问题中实现您所要求的功能:
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中使用。