restricting string input to numbers and letters only

Pages: 12
Dec 6, 2014 at 5:46pm
Hi all, in a part of a program I have to restrict user to input only letters and digits in a string, so I did this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 string name;
bool test;
do {
  test = true;
  cout << "\n\n\tEnter name: ";
  cin >> name;
   for (unsigned short n = 0; n <= name.length()-1; n++){
    if (!(isdigit(name.at(n)) || isalpha(name.at(n))))
    test = false;
}

    if (!test)
    cout << "\n\n\t!ERROR!\n\n";
}
while(!test);


it looks pretty simple and straight forward but unfortunately it accepts space as a valid choice (which I'm not allowed).
And if I stick it into my program (I kept it separately so I don't mess up to much) and I input space it just executes all the loop at once and the program is finished.

So I added this:

1
2
 if (isspace(name.at(n)))
        test = false;


to see if that will help but it does absolutely nothing..

To finish my way to long post I will just say this:
HELP PLEASE!
Dec 6, 2014 at 6:35pm
it accepts space as a valid choice
Actually it is not. operator>> cannot extract whitespaces on default settings. It will stop as soon as it encounters one. Anything after it will remain in input buffer for subsequent reads. So there is no possibility that there would be spaces in your string, so this test does nothing.

example:
1
2
3
4
5
std::string s1, s2;
std::cin >> s1;
std::cout << "S1 is: " << s1 << '\n';
std::cin >> s2;
std::cout << "S2 is: " << s2 << '\n';
Enter string with space in the middle on first prompt and see what happens.
Dec 6, 2014 at 6:45pm
If I want 'space' to be recognized I need to getline!!!!!
So obvious, that was my blond moment of the day...
Thank you
Dec 6, 2014 at 8:18pm
now my program runs for as long as this:

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
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
#include<iomanip>

using namespace std;

int main ()
{
     unsigned short numJudges, numCeleb;
     float score, addScore, finalScore = 0, min, max, max2=0;
     string name, winner;
    do {
     cout << "\n\n\tEnter number of judges: ";
     cin >> numJudges;
     if (numJudges < 3 || numJudges > 6)
        cout << "\n\n\tERROR! Number of judges must be between 3 and 6" << endl;
    }
     while (numJudges < 3 || numJudges > 6);


    do {
     cout << "\n\n\tEnter number of paricipants: ";
     cin >> numCeleb;
     if (numCeleb < 10 || numCeleb > 15)
        cout << "\n\n\tERROR! Number of participants must be between 10 and 15" << endl;
    }
    while (numCeleb < 10 || numCeleb > 15);


     for (unsigned short i = 1; i <= numCeleb; i++){


bool test;
do {
        test = true;
            cout << "\n\n\tEnter name of celebrity " << i << " : ";
            getline (cin, name, '\n');
            for (unsigned short n = 0; n <= name.length() - 1; n++){
                if(!(isdigit(name.at(n)) || isalpha(name.at(n))))
                test = false;
            }
                if (!test)
                cout << "\n\n\tERROR! Name can consist of letters and numbers only.\n";
}
while (!test);


it goes as far as asking for the name and then get : terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at

any idea why? it works when I keep that part of a program separate so I just copied it to my main program but then it crashes..
Dec 6, 2014 at 8:37pm
First problem (crash): n <= name.length() - 1 should be canonical n < name.length() 
Second problem (getline does not get proper input): http://stackoverflow.com/a/21567292
In short: std::getline(std::cin >> std::ws, name);
Last edited on Dec 6, 2014 at 8:37pm
Dec 6, 2014 at 8:42pm
I think I've gotten this error before. Like an array, if you go pass the amount of elements an array, you're going to go out of bounds. So I recommend you check what's going with one of your strings.
Last edited on Dec 6, 2014 at 8:49pm
Dec 6, 2014 at 9:46pm
I changed this to n < name.length () but it didn't help.
I also checked the link you gave above but i just don't get it.
I'm all new to this and we just had like 2 classes on string and that was the only way to getline I know.
But anyway I copied what you gave me there and this time I could actually put in the name and then I got the same 'terminate...'
Dec 6, 2014 at 9:52pm
I changed this to n < name.length () but it didn't help.
Do you still get crash? Same error message?

I also checked the link you gave above but i just don't get it.
That is why I wrote In short line with needed changes to getline
Last edited on Dec 6, 2014 at 9:52pm
Dec 6, 2014 at 9:59pm
Ok I think I've found the problem. This is a cin and getline problem. Your program is skipping the input(particularly the name input). Here is an example with an output.

1
2
3
4
5
6
7
8
9
10
11
12
    string str;
    int x;

    cout << "Enter integer. ";
    cin >> x;

    cout << "Enter string. ";
    getline(cin, str, '\n');

    cout << endl;

    cout << x << " " << str << endl;



Enter integer. 10
Enter string.
10

Process returned 0 (0x0)   execution time : 1.565 s
Press any key to continue.


So you see, your program is skipping your input. This means that your string is empty.

There are many ways to fix this.

first try to use cin.ignore.

If that doesn't work,try cin.ignore(numericlimit<streamsize>::max(, '\n'); // Probably spelled this function but it's in the limits header file so you can look it up.

if that doesn't work, then use a dummy variable to eat up the input buffer.

There are more possible courses of action that you can take to fix this problem but these are the ones I mainly use.
Last edited on Dec 6, 2014 at 10:10pm
Dec 6, 2014 at 10:15pm
Yes I get exactly the same error message. And I did copy your line, but the only think that changed was that this time I was able to input the name and then I got the same error.

deathslice how come str outputs the same as x?

I'm sorry if I'm a bit of a pain, but I am a true beginner and loads of things do not make any sense to me. You would think that if I get assignment, I shouldn't be expected to do anything different than I learned in class, but now they forgot to tell me that there are different ways of getting a line..
Dec 6, 2014 at 10:27pm
Can you post whole code and give an example of input?
Dec 6, 2014 at 10:31pm
first i input number of judges (form 1 to 6) then number of participants (from 10 to 15)
and then I need to input a name of participant

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<iostream>
#include<iomanip>


using namespace std;

int main (){
     unsigned short numJudges, numCeleb;
     float score, addScore, finalScore = 0, min, max, max2=0;
     string name, winner;
    do {
     cout << "\n\n\tEnter number of judges: ";
     cin >> numJudges;
     if (numJudges < 3 || numJudges > 6)
        cout << "\n\n\tERROR! Number of judges must be between 3 and 6" << endl;
    }
     while (numJudges < 3 || numJudges > 6);


    do {
     cout << "\n\n\tEnter number of paricipants: ";
     cin >> numCeleb;
     if (numCeleb < 10 || numCeleb > 15)
        cout << "\n\n\tERROR! Number of participants must be between 10 and 15" << endl;
    }
    while (numCeleb < 10 || numCeleb > 15);


     for (unsigned short i = 1; i <= numCeleb; i++){


bool test;
do {
        test = true;
            cout << "\n\n\tEnter name of celebrity " << i << " : ";
            getline (cin, name, '\n');
            for (unsigned short n = 0; n <= name.length(); n++){
                if(!(isdigit(name.at(n)) || isalpha(name.at(n))))
                test = false;
            }
                if (!test)
                cout << "\n\n\tERROR! Name can consist of letters and numbers only.\n";
}
while (!test);

            addScore = 0,
            min = 6,
            max = 0;

            for (unsigned short a = 1; a <= numJudges; a++){
                do {
                    cout << "\n\n\tEnter score from judge number " << a << " : ";
                    cin >> score;
                    if (score < 0 || score > 6)
                        cout << "\n\n\tERROR! Score must be between 0 and 6." << endl;
                    else if ((((int) (score * 100.0)) % 10) != 0 && ((int) (score * 100.0) % 10) != 9)
                        cout << "\n\n\tERROR! Score can have only one deciamal place" << endl;
                }
                while ((score < 0 || score > 6) || (((int) (score * 100.0)) % 10) != 0 && ((int) (score * 100) % 10) != 9);

                    if (score > max)
                        max = score;

                    if (score < min)
                        min = score;

                        addScore+=score;
                }


                    finalScore = (addScore - max - min) / (numJudges - 2);

                    if (i==1){

                        max2=finalScore;
                        winner=name;
                    }

                    else if(max2<finalScore){

                             max2=finalScore;
                             winner=name;
                           }



                    cout << "\n\n\tFinal score is " << finalScore << endl;
         }

          cout << setw(51) << "And the winner is\n\n" << setw((80+winner.length())/2) << winner << "\n\n"<< setw(42) << max2 << endl;

           return 0;
    }
Last edited on Dec 6, 2014 at 10:31pm
Dec 6, 2014 at 10:36pm
ebunca, str doesn't output the same thing as x(a string can't accept an integer unless you parse it). You can test it out if you want to see for your self. Maybe after you do that, you'll understand your problem better.

In essence, once you enter in a value for x, the input buffer for the getline function gets eaten up and skipped; outputting an empty string.

*Important---Why is your for loop missing a curly bracket( } ) on line 29?
Last edited on Dec 6, 2014 at 10:50pm
Dec 6, 2014 at 10:41pm
You did not fix things I posted about:
1
2
getline (cin >> ws, name);
for (unsigned short n = 0; n < name.length(); n++) {


I did not check line 59, but if there would some problems with it, consider using parentheses to set orde of evaluation.
Last edited on Dec 6, 2014 at 10:46pm
Dec 6, 2014 at 11:06pm
MiiNiPaa I did change them but because I see any improvement I changed it back, the reason I didn't see the improvement is (haha I feel so silly) I actually put in std:: newbies right?

I appreciate you putting up with me, it works now. Thank you for putting your time in it.

death I think I know what your saying I did try it I just misinterpreted it. I see in only puts out x and nothing for string. So is the 'cin >> sw' a normal solution, or there is more surprises waiting for me related to strings.

my for loop closes on line 88 btw

Thanks again
Dec 6, 2014 at 11:10pm
std is not the problem here. It is <= you left was giving you problems.
Dec 6, 2014 at 11:12pm
And yes there is a problem with line 59, but I think I have the solution...
Dec 6, 2014 at 11:21pm
Just as I suspected. I ran your code on c++ shell and as soon as I got to line 36, the program terminated because it skipped that line of code. That is another problem you have beside the one at line 59.
Last edited on Dec 6, 2014 at 11:25pm
Dec 6, 2014 at 11:27pm
MiiNiiPaa fixed line 36 for me, it is fine now.
I appreciate your input, I would never guess that the program would just skip the line. We only did programs with like 1 input of string and than manipulate it. So that's good to know.
Dec 6, 2014 at 11:31pm
you sure? run it on c++ shell(the little icon above your code to the far right).

Also, your program is giving me a warning that suggests you put parentheses around '&&' within '||' [-Wparentheses].
Last edited on Dec 6, 2014 at 11:37pm
Pages: 12