2016-04-19 1 views
8

Я прочитал около 5-10 различных советов, как очистить stdin, но ни один из них не соответствует моим потребностям. Дело в том, что fflush(stdin) отлично работал на моем компьютере, но, к сожалению, он не работает повсюду, поэтому мне нужно что-то с той же функциональностью. Каждый другой способ, который я пробовал, очищает stdin, когда он не пуст, но требует ввода пользователя, когда stdin IS пуст, что означает, что он требует ввода в тот момент, когда я не хочу его получать (+ он все равно отбрасывает).Как очистить stdin перед тем, как получить новый вход?

Вопрос: Могу ли я как-то убедиться, что stdin Пусто, прежде чем я требую ввода пользователем? (А если нет, тогда и только тогда ясно, что так или иначе?) что-то вроде:

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

EDIT: дело в том, что я загружаю символы stdin один за другим, и в какой-то момент, часть входа из предыдущая итерация может или не может быть отброшена. в любом случае, мне нужно очистить stdin, прежде чем я попрошу пользователя ввести другой вход для обработки. Очистка самого буфера не такая уж большая проблема, проблема в том, что происходит, когда вход пуст, когда программа достигает точки очистки stdin, потому что в этот момент программе нужен другой вход, который будет съеден клирингом функция. То, от чего я хочу избавиться. (Когда я мог бы использовать fflush(stdin); я просто знал, что для следующей линии моей программы stdin не будет пустовать ни на что, не задавая никаких вопросов ...)

+2

'fflush (stdin)' is UB. –

+1

Нет такой вещи, как * пустой поток ввода-вывода *, это ** поток **. Рассмотрим:. ./myprog joop

+0

Программирование на окнах, должно работать в linux ... – Tom

ответ

1

TL; DRfflush(stdin) вызываемых программу undefined behavior в соответствии со стандартом , вы никогда не должны использовать его.


Далее в коде (логика), вместо того, чтобы искать строки, вы можете посмотреть на EOF. У этого нет никаких предварительных условий, чтобы stdin должен был иметь входной сигнал перед запуском этого цикла.

Что-то вроде

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

должны соответствовать вашим потребностям.

+0

while (getchar()! = EOF); устанавливает меня в бесконечном цикле, требующем другого и другого ввода. Я также пробовал, если (! Feof (stdin)) и т. Д., Но ничего из этого не сработало. Кажется, что у stdin нет никакого набора EOF, он требует только другого ввода, когда конец будет достигнут. – Tom

+1

По крайней мере, в окнах вам нужно явно генерировать EOF для stdio с помощью Ctrl + Z. – HolyBlackCat

+1

Er, no. Ваш цикл ждет, пока пользователь не генерирует EOF ('^ D' или'^Z'), в то время как OP попросил способ сбросить входной буфер. – jch

1

только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 
+0

'if (tmp [strlen (tmp) - 1]! = '\ N')' является UB, если 'tmp [0] == 0'. Достаточно легко, чтобы первый символ, прочитанный 'fgets()', был нулевым символом. – chux

+0

@chux: правый, но не на ** текст ** файлы. ** Текстовые ** файлы ('stdin', клавиатура, ...) не имеют встроенных NUL. В любом случае, код изменился. Спасибо – pmg

+0

Правда, для первого символа не является нулевым символом. Определение файла _text не является формальным и часто явно не исключает '' \ 0''. Тем не менее, не редко можно прочитать файл UTF-16BE ** text **, в котором отсутствует спецификация (это простой ASCII-файл), который может легко иметь ведущий нулевой символ. Если клавиатура может генерировать нулевой символ или нет, это проблема на уровне платформы, вне контроля программы. ИМО - это хакерский эксплойт и надежный кодекс. чтобы улучшить ответ. – chux

0

select модуль обеспечивает функцию, называемую select, которая достигает именно то, что вы ищете. select.select принимает три аргумента:

select.select(rlist, wlist, xlist) 

Каждый аргумент должен быть список дескрипторов файлов (таких как [sys.sdtin]) и затем ждет, пока конкретная операция ввода-вывода не имеется.Операциями ввода-вывода являются r ead, w обряд или какой-либо другой e x ception по заданным файловым дескрипторам. Он возвращает tuple соответствующих списков, заполненных дескрипторами файлов, которые готовы.

Итак, если есть вход ожидания в sys.stdin то функция будет вести себя следующим образом:

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

Само по себе это не решает проблему, так как по умолчанию функция будет ждать, пока операция ввода-вывода не является доступный. Важно отметить, однако, что select.select имеет необязательный аргумент timeout, обозначающий, как долго он будет ждать, прежде чем сдаться. Нам просто нужно установить тайм-аут на нуль, и мы можем проверить ввод, не блокируя поток программы.

Давайте посмотрим пример, где нет никакого входа ожидания в sys.stdin:

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

Зная, что мы только хотим, чтобы первый элемент этого кортежа (входные потоки), мы готовы сделать полезным, если заявление :

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.

+3

Но вы * did * заметили, что это вопрос C, а не вопрос python? – Jens

+0

@jens/facepalm :-) – dsclose

+0

Отличный ответ. Просто нужен другой вопрос. –

2

Как очистить stdin перед тем, как получить новый вход?
.. поэтому мне нужно что-то с той же функциональностью.

С портативным C это невозможно.


Вместо того, чтобы предложить другую (и более обычно, C) парадигму: Insure предыдущих функций ввода потребляют всех предыдущего ввода.

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; 
} 
Смежные вопросы