I thought I'd paid attention, taken proper notes and had a decent understanding of input validation in C++. There's just one small problem. I'm also taking Java atm and I had confused the two. Nothing I'm trying is working and I have a project due tonight that requires input validation. Now this wouldn't even really be that big of an issue because I could just kinda skirt around the problem except for one small brain twister.
One of the pieces of input we're supposed to collect, verify and utilize is a seating identifier in the format "1A, 4G, or 14C". I've found a solution that Might have worked if not for the fact that the input can be 2 Or 3 characters in length. Later I'll need the number portion and the letter portions to be in Integer format for use as addresses in an array.
So I can collect each potential character as char, but if there are only 2 numbers input that screws things up. Or I can collect it as a string, but I have no idea how to then separate the requisite data. The only way I can think to do this with what I know that I know is if I take the input as a string and one by one compare it to every possible combination of seats and then set the row and seat variables appropriately. While doable, that seems like a positively miserable and wretched way to do things.
So either I need a way to handle the possible 2 characters instead of 3 while still being prepared for 3, or I need a better understanding of the get function so that one by one I can check the characters in the stream for value and existence, then once confirmed place them in appropriate variables, Or I need a way to analyze the parts of a string and then break it apart into the separate components and convert them to integers (I figure for the letter portion I'll just set them with a switch or if statement)
I feel really stupid. I should have asked my teacher about this days ago, but I didn't realize how badly I'd gotten things confused x.x
Any help would be fantastic, Thank you!
(Oh, and it'd be cool if someone would explain to me how to use toupper or tolower, cause even though I -think- I was using them as everyone has shown it, I seem to be missing something)
Oh, important thing! Our teacher currently has us using "using namespace std;" That's kinda a crucial detail there I think x.x
So if I understand you correctly, the seats are in the format <number><letter>?
If so, then you can do this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int number;
char letter;
if (!(std::cin >> number >> letter)) // If we couldn't read a number and another character
{
std::cout << "Hey! What do you think you're doing?!";
// Well, at this point, we failed to read a number followed by a character.
// I don't know what you want to do at this point, but this might be a good start:
std::cin.clear(); // Clear error flags so we can try again
}
// Now, all you know at this point is that you have a number
// (which might be negative or more than 2 digits long)
// and a character (which might not be a letter).
// You'll want to put a few more checks in here.
// (actually, you can just add them to the if statement above)
// Some tips to get started:
// -- You can use std::isalpha to check if it's an alphabetical (letter) character
// -- You can check if the number is one or two digits long by checking that
// it's greater than (or equal to?) 0 and less than 100
And also:
-- Regarding toupper: toupper returns the uppercase version of the character that you pass to it.
It doesn't actually modify that character, if that's where you're getting confused.
So this is wrong:
1 2
char ch = 'a';
std::toupper(ch); // Wrong -- 'ch' is not modified
-- Regarding usingnamespace std; -- all that does is make it so that you can type cout instead of std::cout (which is technically cout's "full name").
Some (a lot) of people recommend you don't use it (just saying).
I've added the std:: part to my code snippets above, but if you're going to use usingnamespace std;, you can safely take those out (though it will work just the same if you leave it in).
Besides regex (regular expressions), one way to sift out the numbers and letters is to use std::stringstream. To use this class, you have to include the <sstream> header.
1 2 3 4 5 6 7 8 9 10 11 12
std::string s = "4A 16G";
std::istringstream ss(s); //First, enter the string into a stream, so we can separate each input
while(ss >> s){ //Reuse s to hold each block of input. This is like using std::cin
std::istringstream iss(s); //Now use a second stream to sift out numbers and letters
int num(0);
iss >> num; //This only extracts the number portion. First, 4, then 16.
char ch('\0');
iss >> ch; //Now grab that last character
//You can also check here if the stream fails, like for example the character is missing
std::cout << "Num: " << num << " / " << "Ch: " << ch << '\n';
}
This way, you won't have to care about how many digits are entered.
So now there is still one small problem - if they enter an integer and nothing But an integer basically then it's just gonna sit there and wait till they either press enter and then another integer, or until they enter something that isn't an integer. I'm not sure how big an issue this is though. Or how to handle it neatly x.x
Hmm...we could try using std::cin.get(letter) instead of std::cin >> letter.
Then, if the user enters just an integer, letter will be a newline character ('\n') instead of an actual letter (and then your std::isalpha check should be able to scoop that up):
1 2 3 4 5 6
int number;
char letter;
if (!((std::cin >> number).get(character)))
{
// Failed to get input in the correct format
}
Alternatively:
1 2 3 4
if (!(std::cin >> number && std::cin.get(character)))
{
// Blah blah...
}
The only problem with that is if the user enters a space in between the number and letter, then the space will get picked up instead of the letter.
But maybe that's what you want.
since I'm using the "using namespace std;" and we haven't gotten to the part of the class yet where he'll explain to us why not to use it and how to do things properly, I'm not totally sure how to interpret the std:: stuff.
Anyway, I bumped into another problem. If I try to use a while loop to continue collecting input in case the input was bad, I end up with an infinite loop :s trying to get it to behave.
So I tried a few different things, I managed to control the length of the loop, but I can't get it to look for new input. my code for this (I've been working on this seperate from my overall program while I sort out how to make it work)
int main()
{
int row;
char seat;
bool validInput = false;
int i =0;
cout <<"Enter Seat in <row><seat> format (1A, 5G, 12C)" <<endl;
while(!validInput && i < 10)
{
validInput = true;
if (((cin >> row).get(seat)))
{
cout << "Row selected is " << row << " seat selected is " << seat << endl;
}
else
{
cout << "Invalid Input format.";
validInput = false;
cout <<"Enter Seat in <row><seat> format (1A, 5G, 12C)" <<endl;
i++;
}
}
cout << "We will now verify that your seat exists."<<endl;
return 0;
}
It gets invalid input and prints "Invalid Input format. Enter Seat in <row><seat> format (1A, 5G, 12C)" ten times and then "We will now verify that your seat exists." and terminates, without ever giving an opportunity to enter different input :s
* edit: I did attempt the loop with the if(!((cin >> row).get(seat))) as well(with the code reflecting the difference oc) with no apparent difference in the loop problem :s
also, this is Only an issue if the input isn't int first.