Validating a string to only have letters with loops.

Hello everyone. I need to validate a string and make sure it ONLY has letters. This is what I have so far and it's not working. No matter what I type, I don't get an error message. What am I doing wrong??

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void name()
{
	string name;
	int i = 0, length = name.length();

	cout << "Enter your name: ";
	cin >> name;

	while (i < length)
	{
		while (!((name[i] <= 'a' && name[i] >='z' ) || (name[i] <= 'A' && name[i] >= 'Z') || name[i] == ' ' || name[i] == '\n'))
		{
			cout << "Error -- Invalid name; try again: ";
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');
			cin >> name;
		}
		i++;
	}

        cout << name;
}
Last edited on
You could try using the ASCII codes of each character and check if it's within the range of the alphas :

1
2
3
4
5
6
7
8
9
10
11
...
string name = "Lewis";
for (int i = 0; i < name.size(); i++)
{
    if ((int)(name[i]) < [Ascii of chars_start] || (int)(name[i]) > [Ascii of chars_end])
        {
            return false;
        }
return true;
}


1
2
char x = 'x';
int ascii_x = (int)x; // This is what (int) does, it returns the ascii code of a char. 


Something like that, I didn't try it in VS tho.
Last edited on
I'm trying it on VS, does this need a new #include header, or did you literally mean the the start number of the ASCII?

Update: I tried using the code with the ASCII value of the letters and that did not work.
Last edited on
You could do something like 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
#include <iostream>
#include <string>
using namespace std;

bool IsLetters(string input)
{
	for (int i = 0; i < input.size(); i++)
	{
		int uppercaseChar = toupper(input[i]); //Convert character to upper case version of character
		if (uppercaseChar < 'A' || uppercaseChar > 'Z') //If character is not A-Z
		{
			return false;
		}
	}
	//At this point, we have gone through every character and checked it.
	return true; //Return true since every character had to be A-Z
}


int main() 
{
	string x = "ABCD";
	if (IsLetters(x))
	{
		cout << "String: " << x << " only contains letters." << endl;
	}
	else
	{
		cout << "String: " << x << " does NOT only contains letters." << endl;
	}

	string y = "ABCD1234";
	if (IsLetters(y))
	{
		cout << "String: " << y << " only contains letters." << endl;
	}
	else
	{
		cout << "String: " << y << " does NOT only contains letters." << endl;
	}

	return 0;
}
http://www.kerryr.net/pioneers/ascii2.htm

This can maybe help you :

Uppercase letters go from 65 to 90 and lower case from 97 to 122 so :

1
2
3
4
 if ((int)(name[i]) < 65 || ((int)(name[i]) > 90 && (int)(name[i]) < 97) || (int)(name[i]) > 122)
        {
            return false;
        }


So you're basically checking if the ASCII code is within [65;90]U[97;122]
I literally tried both of these on VS right now, and they did not work.

Pindrought, I am still not getting any errors.

Vilarge, I that's exactly how I did it last night and I'm not getting any error codes or the "good job" code i added.

I added a system("pause") at the end of the code when I tried it both ways just to see if I was missing anything and it's validating it as correct.
Care to post your function / part of the program updated so I can check it out ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>

using namespace std;

int main()
{
	string name;
	cout << "Enter a name : " << endl;
	getline(cin, name);
	for (int i = 0; i < name.size(); i++)
	{
		cout << (int)name[i] << endl;
	}
	system("pause");
	return 0;
}


This is the core of what you wanna do, it's gonna show you a number which represent the ASCII value of the 'char' ([i] index of the string name). Then you check out if that number is within the range I told you yesterday :


So you're basically checking if the ASCII code is within [65;90]U[97;122]


P.S. : I would help more, but this is school stuff, and I know for sure you ain't gonna learn if somebody do the hard stuff for you :P Good luck and if you need anything, keep posting here !
Last edited on
So after tons of trial and errors, I finally got it to somewhat work. Except now I'm getting an error code from VS saying "Expressions: string subscript is out of range" on my IF expression. Any idea why?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void name()
{
	string name;
	int i;

	cout << "Enter your name: ";
	cin >> name;

	for (i = 0; i < sizeof(name); count++)
	{
		if ((name[count] >= '0' && name[count] <= '9') || name[count] == '\n')
		{
			cout << "Error. Enter your name: ";
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');
			cin >> name;
		}
	}
}


Also, thank you so much for your help, I really appreciate it.
Last edited on
Line 4: It's a poor practice to name a variable the same as your function. The compiler knows the difference, but it's confusing to the reader.

Line 11: The termination condition of your for loop is wrong. You want <, not >. This is the cause of your subscript out of range.

Line 11: You're incrementing count. Where is count defined? Don't you want to be incrementing your loop variable (i)?

Line 13: That's going to test only if a character is numeric. What if the character is a special character? The isalpha() function is ideal for testing if a character is alphabetic.
http://www.cplusplus.com/reference/cctype/

Line 13: count is undefined. Again, you want your to use your loop variable, i.

Line 13: The test for \n is unneeded. The cin at line 9 will discard the \n.

Lines 15-18: This is going to be repeated for each character that doesn't pass. You really only want to display the message once. Here's a variation on the bool function pindrought gave you.
1
2
3
4
5
6
7
bool IsLetters(const string & input)
{  for (size_t i = 0; i < input.size(); i++)
    {  if (! isalpha(input[i])) 
          return false;  // character is not alphabetic
    }
    return true;  // Every character is alphabetic 
}


Line 18: If the test fails, you input name again, but you don't start testing from the beginning. You start from where ever the previous test failed. i.e. If the third character fails, after inputting the name again, you're skipping characters 0-3.

Line 21: name (the variable) goes out of scope when the function exits. Presumably you want to return name to the caller. How are you doing this?
Last edited on
Line 4: The name validation keeps messing up the flow of a math game I'm making. I am working on the name function on a different project so that I don't mess up everything I've already perfected. In my final draft I have my function is called userName().

count: I was changing all the i's because I had used that in another counter in the program and did not want to cause a confusion in the two separate counters.

line 18: The error message is showing up only once.

Also, the inputed name is going to be saved as the name of a file, once I am able to get the input validation to work right.

Finally, according to my professor, adding the cin.clear and in.ignore clears any previous user input. Which is why I keep adding it. Is he wrong?

Sorry I wasn't detailed earlier.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void userName()
{
	string name;
	int count;

	cout << "Enter your name: ";
	cin >> name;

	for (count = 0; count < sizeof(name); count++)
	{
		if (name[count] >= '0' && name[count] <= '9')
		{
			cout << "Error. Enter your name: ";
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');
			cin >> name;
		}
	}
}
Last edited on
line 9: sizeof(name) is incorrect. Sorry I didn't catch that before. You want name.size().

line 11: Your if statement will only detect numbers as illegal. As I asked before, what if the user enters special characters such as $?

line 18: The error message is showing up only once.

Well yes, that's because you reprompt for the name, but you still have the problem of skipping characters when the name is re-input. Consider if the user enters ABC9. You're going to execute the loop 4 times. On the fourth character (i=3), You cout "error" and input a new name. Fine, except the new value of name is NOT going to be checked at all since you exit the loop because you've reached the termination condition (i<name.size()).

I strongly recommend using the IsLetters() function I posted earlier. This will prevent the problem of not testing the entire name if it is reentered. Putting the alpha checking is a separate function will simplify your code..

Also, the inputed name is going to be saved as the name of a file, once I am able to get the input validation to work right.

Fine, but you didn't answer my question how you're returning name to the calling code.

Finally, according to my professor, adding the cin.clear and in.ignore clears any previous user input. Which is why I keep adding it. Is he wrong?

No. It's good practice to clear the input.










I was trying to do this without isalpha. Anyway, I gave in for now. Thanks for the sizeof(name) pointer. It was the last thing I changed and the program runs smoothly.

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
using namespace std;

bool letters(string n);

int main()
{
	string n;
	bool let;

	cout << "Enter your name: ";
	cin >> n;

	// Call letter validation function.
	let = letters(n);

	// If name was not right, ask them to re-input name.
	while (let == false)
	{
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "Error!! Enter your name: ";
		cin >> n;

		letters(n);
	}
	
	if (let == true)
	{
		cout << "Your name is ";
		cout << n;
	}

	return 0;
}

bool letters(string n)
{
	int i;

	for (i = 0; i < n.size(); i++)
	{
		if (!(isalpha(n[i])))
		{
			return false;
		}
		return true;
	}
}
Two problems remain:

line 24: Does not set let to the result of letters. You're calling letters and ignoring the result. Therefore when you loop back up to line 17, you're testing the result from the first name.

line 46: Your return true[ is in the wrong place. It should be after line 47. As it is now, you're going to return true on the first letter that is alpha. You only want to return true after you have checked all the letters.

Line 27: The if statement is not needed. When you exit the while loop, let can only be true.


I just set if (let) so there is no chance the game will continue unless name is only letters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool letters(string n)
{
	int i;

	for (i = 0; i < n.size(); i++)
	{
		if (!(isalpha(n[i])))
		{
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');
			cout << "Enter your name: ";
			cin >> n;
			i = 0;
		}
		return true;
	}
}
Last edited on
Your return true is STILL in the wrong place.

Consider if the first entry is not alpha. You reprompt for the name at line 12 and set i back to zero. Fine. Now, what is the next statement executed after that? line 15. You return true without ever checking the second name. You should only return true after all the character positions have been checked. Hence, return true belongs AFTER line 16, not before.
Topic archived. No new replies allowed.