C++ Input validation

So I feel really really stupid right about now.

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

Think that solved my problem!Thanks so much!

simultaneously solved and created problems =D x.x

^_^ all fixed! Thanks everyone!
Last edited on
The strings you're using, are they: char str[]; or string str;?

1
2
3
char x = A; // x == 'A'
tolower ( x ); // x == 'A'
x = tolower ( x ); // x == 'a' 
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 
And this is correct:
1
2
char ch = 'a';
ch = std::toupper(ch); // Right -- 'ch' becomes 'A' 

-- Regarding using namespace 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 using namespace 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.

Edit:
I type way too slow. :(
Last edited on
Long, That will work perfectly! Thank you so much!
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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.
Last edited on
Any Thoughts?
I think, therefore I am.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

using namespace std;

int main ( )
{

    int row;

    char seat;

    while ( true )
    {
        cout << "Enter Seat in <row><seat> format (1A, 5G, 12C): ";

        if ( ( cin >> row ).get( seat ) && isalpha ( seat ) )
        {
            cout << "\nYou selected row " << row << " seat " << seat << ".\n\n";
            break;
        }

        else
        {
            cout << "\nInvalid Input format. ";
            cin.clear ( );
            cin.sync ( );
        }
        
    }

    cout << "We will now verify that your seat exists.\n\n";
}

It doesn't work if you only input a number though. I'll try to fix that.

Edit: Fixed
Last edited on
Thank you very much! That fixed it. I keep forgetting about cin.clear >.<
Topic archived. No new replies allowed.