(gelöst) Benutzereingabe "1" OK "1 a" nichtOK!



  • b1419589 schrieb:

    [...] (Dass die Eingabe von "Leerzeichen" + 1 immer noch als 1 akzeptiert wird, spielt keine Rolle.) [...]

    Gefixt. Hatte im Original fälschlicherweise std::skipws statt richtig std::noskipws .



  • @Swordfish, dankeschön! Alles perfekt! Damit wurden alle meine Probleme gelöst und Fragen beantwortet.



  • #include <cctype>    // std::isspace()
    #include <limits>    // std::numeric_limits<>::max()
    #include <iomanip>   // std::noskipws()
    #include <iostream>
    
    bool only_whitespace(std::istream & is)       // true, wenn nur white-space Zeichen in is sind.
    {
    	std::istream::int_type ch = 0;
    
    	// solange das naechste Zeichen in is
    
    	while (ch != '\n' && ch != EOF              // kein Newline ist und auch das Streamende nicht erreicht ist
    		&& std::isspace(ch = is.peek())    // und ein Leerzeichen, Tab, ... ist (peek() nur ansehen, nicht extrahieren)
    		)
    	{
    		is.get();                               // extrahiere das Zeichen aus is (= werfe das angesehene Zeichen weg).
    	}
    
    	return ch == '\n' || ch == EOF;             // ist die while()-Schleife wegen '\n' oder EOF abgebrochen?
    	// wenn nicht, war es ein anderes Zeichen das nicht isspace() ist.
    }
    
    int main()
    {
    	int choice;
    	for (choice = 0; std::cout << "Input: " && !(std::cin >> std::noskipws >> choice) || !only_whitespace(std::cin) || (choice < 1 || 4 < choice);choice++)
    	{
    		std::cerr << "Input error!\n\n";    // eine Fehlermeldung ausgeben
    		std::cin.clear();                   // Fehlerflags loeschen, falls der Extraktionsversuch fehlgeschlagen ist
    
    		std::cin.ignore(                    // weitere Zeichen in cin ignorieren
    			std::numeric_limits< std::streamsize >::max(), // Anzahl zu ignorierender Zeichen, vorsichtshalber die groesztmoegliche Anzahl annehmen
    			'\n'                            // solange kein '\n' daherkommt
    			);
    	}
    	std::cout << choice << "\n\n";          // getroffene Auswahl ausgeben
    }
    


  • und? was bringt die Nachplapperei?



  • Die for-Schleife ist nicht richtig!!!



  • Wie wärs mit

    std::string str;
    std::getline(std::cin, str);
    int choice = boost::lexical_cast<int>(str); // Wirft Exception wenn str nicht nach int konvertiert werden kann
    

    ?



  • Es gibt an der for-Schleife nichts auszusetzen. Sie macht genau das, was Swordfish mit einer do-while-Schleife auch macht!



  • hustbaer schrieb:

    Wie wärs mit

    std::string str;
    std::getline(std::cin, str);
    int choice = boost::lexical_cast<int>(str); // Wirft Exception wenn str nicht nach int konvertiert werden kann
    

    ?

    Danke hustbaer, aber boost ist für mich jetzt nochmal eine neue Bibliothek. So lerne ich die Grundlagen nicht, wenn ich ständig auf eine Bibliothek ausweiche.
    Mit Boost Lexical_cast ist die Konvertierung von string to z.B. int sicherlich einfacher oder besser. Danke für deine Antwort.



  • MarkusMundM schrieb:

    #include <cctype>    // std::isspace()
    #include <limits>    // std::numeric_limits<>::max()
    #include <iomanip>   // std::noskipws()
    #include <iostream>
    
    bool only_whitespace(std::istream & is)       // true, wenn nur white-space Zeichen in is sind.
    {
    	std::istream::int_type ch = 0;
    
    	// solange das naechste Zeichen in is
    
    	while (ch != '\n' && ch != EOF              // kein Newline ist und auch das Streamende nicht erreicht ist
    		&& std::isspace(ch = is.peek())    // und ein Leerzeichen, Tab, ... ist (peek() nur ansehen, nicht extrahieren)
    		)
    	{
    		is.get();                               // extrahiere das Zeichen aus is (= werfe das angesehene Zeichen weg).
    	}
    
    	return ch == '\n' || ch == EOF;             // ist die while()-Schleife wegen '\n' oder EOF abgebrochen?
    	// wenn nicht, war es ein anderes Zeichen das nicht isspace() ist.
    }
    
    int main()
    {
    	int choice;
    	for (choice = 0; std::cout << "Input: " && !(std::cin >> std::noskipws >> choice) || !only_whitespace(std::cin) || (choice < 1 || 4 < choice);choice++)
    	{
    		std::cerr << "Input error!\n\n";    // eine Fehlermeldung ausgeben
    		std::cin.clear();                   // Fehlerflags loeschen, falls der Extraktionsversuch fehlgeschlagen ist
    
    		std::cin.ignore(                    // weitere Zeichen in cin ignorieren
    			std::numeric_limits< std::streamsize >::max(), // Anzahl zu ignorierender Zeichen, vorsichtshalber die groesztmoegliche Anzahl annehmen
    			'\n'                            // solange kein '\n' daherkommt
    			);
    	}
    	std::cout << choice << "\n\n";          // getroffene Auswahl ausgeben
    }
    

    @MarkusMundM, nein diese Schleife macht nicht dasselbe, was Swordfish bereits mit einer do-while Schleife gelöst hat.



  • OK.
    Aber du kannst ja mal reingucken wie Boost es macht 😉
    IIRC verwenden die nen (etwas modifizierten und auf etwas bessere Geschwindigkeit modifizierten) Stringstream.
    Da wird dann erstmal der Ausgangswert "reingeschiftet" (stream insertion, "<<" halt).
    Und dann wird versucht das "rauszushiften" (stream extraction, ">>") was man haben möchte.

    Und dann wird geprüft
    a) Ob der Stream danach noch "good" ist und
    b) Ob der Stream danach leer ist

    Wenn beides zutrifft war die Konvertierung erfolgreich.

    Finde ich weitaus eleganter als direkt in cin zu gucken ob auch wirklich ein Newline das nächste Zeichen ist.


Anmelden zum Antworten