2016-04-19 5 views
8

Ich habe ungefähr 5-10 verschiedene Ratschläge gelesen, wie man Stdin löscht, aber keiner von ihnen passt zu meinen Bedürfnissen. Die Sache ist, dass fflush(stdin) perfekt an meinem Computer funktioniert, aber leider scheint es nicht überall zu funktionieren, also brauche ich etwas mit der gleichen Funktionalität. Jede andere Art, die ich versuchte, löscht Stdin, wenn es nicht leer ist, aber erfordert Benutzereingaben, wenn stdin leer ist, was bedeutet, dass es Eingaben in einem Moment benötigt, den ich nicht bekommen möchte (+ es wirft es trotzdem ab).Wie lösche ich die Standardeingabe, bevor ich eine neue Eingabe erhalte?

Die Frage ist: Kann ich irgendwie sicherstellen, dass stdin IS leer ist, bevor ich Benutzereingaben benötige? (Und wenn nicht, dann und nur dann klar, dass es irgendwie?) so etwas wie:

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

EDIT: die Sache ist, dass ich Zeichen laden von stdin eins nach dem anderen und irgendwann, einen Teil der Eingabe von vorherige Iteration könnte oder wird nicht verworfen. So oder so, ich brauche clear stdin, bevor ich den Benutzer für eine andere Eingabe, die verarbeitet werden soll. Das Löschen des Puffers selbst ist keine so große Sache, das Problem ist, was passiert, wenn die Eingabe leer ist, wenn das Programm zum Löschen stdin kommt, weil das Programm in diesem Moment eine andere Eingabe benötigt, die von der Reinigung aufgefressen wird Funktion. Das will ich loswerden. (Wenn ich fflush(stdin); verwenden kann ich wusste nur, dass für die nächste Zeile meines Programms der stdin leer sein wird, egal was, keine Fragen gestellt ...)

+2

'fflush (stdin)' ist UB. –

+1

Es gibt keinen * leeren I/O-Stream *, es ist ein ** Stream **. Betrachte: './myprog joop

+0

Programmierung auf Windows, muss bei Linux arbeiten ... – Tom

Antwort

1

TL; DRfflush(stdin) Invokes undefined behavior gemäß der Norm Du solltest es niemals benutzen.


, um Ihren Code Coming (Logik), anstatt für eine neue Zeile zu suchen, können Sie für EOF suchen. Es ist nicht erforderlich, dass stdineinige Eingang vor dem Ausführen dieser Schleife haben sollte.

So etwas wie

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

sollten Ihre Bedürfnisse erfüllen.

+0

while (getchar()! = EOF); versetzt mich in eine Endlosschleife, die eine andere und eine andere Eingabe erfordert. Ich habe auch versucht, wenn (! Feof (stdin)) usw., aber nichts davon hat funktioniert. Es sieht so aus, als hätte stdin kein EOF gesetzt, es benötigt nur eine andere Eingabe, wenn das Ende erreicht ist. – Tom

+1

Zumindest bei Windows müssen Sie explizit EOF für stdio mit Strg + Z generieren. – HolyBlackCat

+1

Er, nein. Ihre Schleife wartet, bis der Benutzer ein EOF ('^ D' oder'^Z') generiert, während das OP nach einer Möglichkeit fragt, den Eingabepuffer zu löschen. – jch

1

Verwenden Sie nurfgets(), um stdin zu lesen.

Verwenden Sie einen Puffer, der groß genug ist, und/oder testen Sie ihn auf volle Zeilen.

Mit fgets() müssen Sie sich nie um zusätzliche Zeichen in stdin kümmern.

// 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')' ist UB wenn 'tmp [0] == 0'. Einfach genug, dass das erste Zeichen mit 'fgets()' als Null-Zeichen gelesen wird. – chux

+0

@chux: richtig, aber nicht ** Text ** Dateien. ** Text ** -Dateien ('stdin', die Tastatur, ...) haben keine eingebetteten NULs. Der Code wurde geändert, um das trotzdem zu beheben. Danke – pmg

+0

Wahr, es ist nicht üblich, dass das erste Zeichen das Nullzeichen ist. Die Definition einer _text-Datei_ ist nicht formell und schließt oft ein '' 0'' nicht ausdrücklich aus. Dennoch ist es nicht selten, eine UTF-16BE ** text ** -Datei zu lesen, der eine BOM-Datei fehlt (es ist eine einfache ASCII-Datei), die leicht ein führendes Nullzeichen haben kann. Wenn eine Tastatur ein Nullzeichen generieren kann oder nicht, handelt es sich um ein Problem auf Plattformebene, das über die Kontrolle des Programms hinausgeht. IMO ist es ein Hacker-Exploit und robuste Code-Copes. up Abstimmung für verbesserte Antwort. – chux

0

Das select Modul bietet eine Funktion select genannt, die genau das, was Sie suchen erreicht. select.select hat drei Argumente:

select.select(rlist, wlist, xlist) 

Jedes Argument eine Liste von Datei-Deskriptoren (wie [sys.sdtin]) sein sollte, und es wartet dann, bis ein bestimmte IO-Betrieb zur Verfügung steht.Die IO-Operationen sind r ead, w rite oder einige andere e x ception auf den angegebenen Dateideskriptoren. Es gibt tuple der entsprechenden Listen zurück, die mit den Dateideskriptoren gefüllt sind, die bereit sind.

Also, wenn es Eingang in sys.stdin wartet dann würde die Funktion wie so verhalten:

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

Von selbst, das löst nicht das Problem, da standardmäßig wird die Funktion warten, bis ein IO-Betrieb verfügbar. Wichtig ist jedoch, select.select hat ein optionales timeout Argument, das angibt, wie lange es warten wird, bevor es aufgibt. Wir müssen das Timeout einfach auf Null setzen und können nach Eingaben suchen, ohne den Programmablauf zu blockieren.

Nehmen wir ein Beispiel sehen, wo es keinen Eingang in sys.stdin wartet:

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

Zu wissen, dass wir nur das erste Element dieses Tupel wollen (die Eingangsströme) wir sind bereit, ein sinnvoll, wenn Aussage zu machen :

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

, dass der Eingangsstrom braucht nur etwas Iteration bedeutet Clearing:

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

Und wir können dies natürlich auf jedem Eingangsstrom verwenden, läßt es so setzt in einer Funktion:

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() 

Also lassen Sie sich unsere Funktion demonstrieren zu erreichen, was Sie in Ihrer Frage stellen:

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) 

Die clear_input-Funktion kann als blockierungsfreie Möglichkeit zum Löschen von Eingabeströmen verwendet werden und sollte in Python2 und Python3 funktionieren.

+3

Aber Sie * haben * bemerkt, dass dies eine C-Frage ist, keine Python-Frage? – Jens

+0

@jens/facepalm :-) – dsclose

+0

Große Antwort, obwohl. Braucht nur eine andere Frage. –

2

Wie kann ich die Standardeingabe löschen, bevor ich eine neue Eingabe erhalte?
.. also brauche ich etwas mit der gleichen Funktionalität.

Mit tragbaren C ist dies nicht möglich.


vorschlagen stattdessen ein anderes (und mehr üblich C) Paradigma: Versichern vorherige Eingabefunktionen all die vorherige Eingabe verbrauchen.

fgets() (oder * nix getline()) ist der typische Ansatz und löst die meisten Situationen.

Oder rollen Sie Ihre eigenen. Folgendes verbraucht, speichert jedoch keine zusätzlichen Eingaben.

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; 
} 
Verwandte Themen