R00ki3 M1stak3
R00ki3 M1stak3

Reputation: 97

Input validation to filter out chars, strings, and a range of ints

I have looked in several places on the Internet but cannot find what I am looking for. Basically I am trying to understand data validation and filter out all user input except either the number 1 or 2. I have found information for validating ints. Found stuff on filtering out chars and strings. But when I try to put them together it doesn't work. Basically if the user enters something that is not 1 or 2, it does not end a loop asking for correct input.

I have included more details in the comments in the code below.

Any help is appreciated!

#include <iostream>
#include <string>

int main()
{
    std::cout << "Please enter 1 or 2.  No other numbers or characters." 
        << std::endl;

    std::string numberString;

    //Used a string so if the user enters a char it gets converted to an 
    //integer value of 0.
    getline(std::cin, numberString);
    int numberInteger = atoi(numberString.c_str());

    //If the user enters the wrong number, char, or string, 
    //the program goes to this area of code.  
    //But if a subsequent correct entry is made, the loop does not end.
    if (numberInteger < 1 || numberInteger > 2)
    {
        do
        {
            //Tried using these two lines of code to clear the input buffer, 
            //but it doesn't seem to work either:
            //std::cin.clear();
            //std::cin.ignore(std::numeric_limits <std::streamsize>::max(), '\n');

            std::cout << "Invalid input.  Please enter 1 or 2.  No other numbers or characters." 
            << std::endl;
            getline(std::cin, numberString);
            int numberInteger = atoi(numberString.c_str());
        } while (numberInteger < 1 || numberInteger > 2);
    }

    else
    {
        std::cout << "You entered either 1 or 2.  Great job! " 
        << std::endl;
    }

    return 0;
}

Upvotes: 1

Views: 620

Answers (1)

Swordfish
Swordfish

Reputation: 13134

#include <cctype>
#include <limits>
#include <iostream>

std::istream& eat_whitespace(std::istream& is)
{
    int ch;
    while ((ch = is.peek()) != EOF && ch != '\n' &&
           std::isspace(static_cast<char unsigned>(ch))) // 0)
        is.get();  // As long as the next character
                   // is a space, get and discard it.
    return is;
}

int main()
{
    int choice;
    while (std::cout << "Please enter 1 or 2. No other numbers or characters: ",
           !(std::cin >> std::skipws >> choice >> eat_whitespace) ||  // 1)
           std::cin.peek() != '\n' ||  // 2)
           choice < 1 || 2 < choice) {  // 3)
        std::cerr << "I said 1 or 2 ... nothing else ... grrr!\n\n";
        std::cin.clear();  // 4)
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // 5)
    }

    std::cout << "Input was " << choice << '\n';
}

0) Don't feed isspace() negative values.
1) Extraction of an int failed. Allow whitespace before and after the int.
2) If the next character in the stream is not a newline character, there is garbage left eat_whitespace() didn't swallow --> complain.
3) choice not in range.
4) clear flags to make sure input functions will work again.
5) ignore up to maximum streamsize characters untill the next newline.

Upvotes: 1

Related Questions