Sign in to follow this  
Grahf750

input validation

Recommended Posts

Grahf750    122
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.

Share this post


Link to post
Share on other sites
mike74    100
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.


Share this post


Link to post
Share on other sites
Zahlman    1682
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.

Share this post


Link to post
Share on other sites
Motz    136
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 :-)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this