input validation

Started by
4 comments, last by Motz 18 years, 9 months ago
What would be the best way to check if a number is between 1 and 3? Now I want to account for any situation such as the user could type a sentence, a large number, a character whatever and until it is a number between 1 and 3 it won't let it go through.
Advertisement
Umm, what language are you using?
I'm assuming you're using C/C++.

Just make sure the string contains only digits and the period.

Then do an atof on the string and make sure the result is between 1 and 3.

Mike C.
http://www.coolgroups.com/zoomer/

Quote:Original post by Grahf750
What would be the best way to check if a number is between 1 and 3? Now I want to account for any situation such as the user could type a sentence, a large number, a character whatever and until it is a number between 1 and 3 it won't let it go through.


Mike C.http://www.coolgroups.com/zoomer/http://www.coolgroups.com/ez/
Quote:Original post by Grahf750
What would be the best way to check if a number is between 1 and 3? Now I want to account for any situation such as the user could type a sentence, a large number, a character whatever and until it is a number between 1 and 3 it won't let it go through.


Strongly recommend that you separate this into two steps: check it's a number, and then check that the number is in range. With the normal C++ formatted (text) IO (i.e. using operator>> on an input stream), reading in to an integer-typed value "fails" if the data is invalid; to continue reading, you must "reset" the stream, and then you generally want to skip past that data by "ignore"ing it.

More information here, but basically a general-purpose solution looks like (this is off the top of my head):

// Grab a value of type T from the input stream, which is between low and high// (inclusive). Skip to the next line of data upon failure.template <typename T>T getValue(const istream& is, const T& low, const T& high) {  T result;  // Until we can read in a T, and it's in range...  while(!(is >> result && result >= low && result <= high)) {    // Until that's true (i.e. while it's false), we have an error, so handle it    // One pathological case is "end of input" with nothing valid    // We'll throw an exception in that case.    if (is.eof()) { throw exception("No valid value before end of input"); }    is.clear();    // Skip past arbitrarily many characters (we ask the standard library for    // a number that represents "the greatest possible size of a stream"), up    // until a '\n' occurs.    is.ignore(numeric_limits<streamsize>::max(), '\n');  }  return result;}


Or, a variation:

// This time, the input will always be grabbed a line at a time, and we will// only accept a line which begins with a valid value and has no more data// after that (except possibly some trailing whitespace).template <typename T>T getValue(const istream& is, const T& low, const T& high) {  string line; // will hold successive lines from the stream.  // Read lines until we are successful or it is no longer possible to read.  while(getline(is, line)) {    T candidate; // possible result.    char garbageHolder;    // Parse the line into a temporary, then whitespace, then a character.    // If we were able to read the character, then there is garbage after our    // item, and we reject the line. Of course we must reject it right away    // if we can't read the T :)    // To do the parsing, we load the line into a stringstream :)    stringstream ss(line);    if ((ss >> candidate) && !(ss >> ws >> garbageHolder) && // line has right stuff        (candidate >= low) && (candidate <= high)) { // item is in range      return candidate; // breaking out of the loop too, of course    }    // If it failed, we'll try again from scratch with the next line.    // Thus there is no need for any resetting or ignoring, because getline()    // always works as long as there is more input.  }  // If we get here, there are no more lines to read.  throw exception("No valid value before end of input");}


You will need to include <iostream> (of course), <limits> (for the std::numeric_limits class and its max() function), <exception> (for std::exception), <string> (for std::string) and <sstream> (for std::stringstream); and indicate things that are in the std namespace where appropriate (either qualify them with std:: in the code given, or use appropriate 'using' statements).

As an exercise, modify these:

i) so that they always use cin for input, and remove the istream parameter (since it will no longer be needed);
ii) so that they accept a 'const std::string& prompt' parameter, which is a prompt for input, and outputs this to cout before each attempt to grab input.
I didn't mean for files just basic console user input
The same applies for console input as for files. std::cin behaves like a file in many respects, so it's no great hassle to remove the file openning code and just stream the data directly from cin as you would with normal console input :-)

This topic is closed to new replies.

Advertisement