Vaildator for a string on user input - c++

Hey i want to stop the user from entering integers when i ask the user to input a name. I have achieved this for an integer and a char. Can anyone help me adapt my code for a string.
int getNum()
{
int num;
std::cout << "\nWhat is your age? ";
while (!(std::cin >> num))
{
// reset the status of the stream
std::cin.clear();
// ignore remaining characters in the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Enter an *integer*: ";
}
std::cout << "You entered: " << num << std::endl;
return num;
}
char getChar(string q)
{
char input;
do
{
cout << q.c_str() << endl;
cin >> input;
}
while(!isalpha(input));
return input;
}

string q = "This is a test123";
for(string::iterator i = q.begin(); i != q.end(); i++)
{
if((*i < 'A' || *i > 'z') && (*i != ' '))
{
return false;
}
}
would also be an option, if you allow for spaces and other characters.
Edit: updated for checking a single char:
char c;
bool finished = false;
printf("Please enter your sex, M/F?\n");
while(!finished)
{
cin >> c;
if(!(c == 'm' || c == 'M' || c== 'f' || c=='F'))
{
printf("Please try again...\n");
}
else
{
finished = true;
}
}
Note that c is only input, char by char, when Enter is pressed, before that the line feed does not happen.

If you plan on using std:string, then you can use this to find if the entered string has any digits or not:
if (std::string::npos != s.find_first_of("0123456789"))
{
std::cout << "digit(s)found!" << std::endl;
}

Related

Asking for user input more than once in a while loop

I am currently writing a program that translates normal text to whale talk (in case you want to know what whale talk is, it is the statement ripped of consonants with u's and e's doubled)
I successfully wrote the program. But I want it to be repeated again and go through the same process until we manually exit it.
For this I used a while loop and used exit as variable. But it didn't work as expected as on second time around it did not ask for input but displayed the prompt text and skipped to the exit/no exit line.
Can you tell me what is wrong with my program? Here is my code (you can try to compile and execute it yourself):
#include <iostream>
#include <string>
#include <vector>
int main(){
bool exit = false;
//Open
std::cout<<"==========\n";
std::cout<<"WHALE TALK\n";
std::cout<<"==========\n";
std::cout<<"\n";
//main loop
while (!exit){
//Variables
std::vector<char> whaletalk;
//input
std::string input;
std::cout<<"Type the text you want to translate to whale language: ";
getline(std::cin,input);
std::cout<<"\n\nWhale talk: ";
//vowels
std::vector <char> vowels = {'a','e','i','o','u'};
//sorter
//iterating through string
for (int i = 0; i < input.size(); i++){
//iterating through vowels
for (int j = 0; j < vowels.size(); j++){
//case of vowels
if(input[i] == vowels[j]){
//case of u and e
if ((input[i] == 'u') or (input[i] == 'e')){
whaletalk.push_back(input[i]);
whaletalk.push_back(input[i]);
}
//case of vowels other than u and e
else {whaletalk.push_back(input[i]);}
}
}
}
//Output
for (int k = 0; k < whaletalk.size(); k++ ){
std::cout<<whaletalk[k];
}
std::cout<<"\n";
// exit/no exit
std::string response;
std::cout<<'\n';
std::cout<<"Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin>>response;
if (response == "NO" or response == "no" or response == "No"){
exit = true;
}
}
}
Here is an image of the bug
When you use the >> operator to read a string, it only reads the next word (up to a whitespace character), and leaves everything else on the input stream, but std::cin still blocks until a new line (enter is pressed).
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin >> response;
if (response == "NO" or response == "no" or response == "No") {
exit = true;
This leaves just the newline in the buffer if you only typed one word (if you did say "a b" then it would leave "b\n" and response would be "a", not "a b"), and so the next std::getline will give you what was left, in this case an empty line.
int main()
{
std::string str;
std::cout << "Enter word: ";
std::cin >> str;
std::cout << "Entered '" << str << "'" << std::endl;
std::cout << "Enter line: ";
std::getline(std::cin, str);
std::cout << "Entered '" << str << "'" << std::endl;
}
Enter word: a
Entered 'a'
Enter line: Entered ''
Or if you have a space character:
Enter word: aa bb
Entered 'aa'
Enter line: Entered ' bb'
You could just always use std::getline when reading just string responses to avoid missing anything by accident (like that " bb").
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::getline(std::cin, response);
if (response == "NO" or response == "no" or response == "No") {
exit = true;
Or after any other >> operations to get whatever is "remaining" and proceed to the next line.
Another possibility is to use std::istream.ignore() to ignore remaining input up to a maxmium length and delimiter:
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin >> response;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (response == "NO" or response == "no" or response == "No") {
exit = true;
In this case std::numeric_limits<std::streamsize>::max() means any amount, up to the next line \n. If the user entered say "no abc", then "abc" would be lost.
You should put these function to clear input and ignore all character except break line character:
std::cin.clear();
std::cin.ignore(32767, '\n');
below this function:
std::cin >> ...;
Here is the loop check for response:
while (true) {
if (response == "NO" or response == "no" or response == "No") {
exit = true;
break;
}
else if (response == "YES" or response == "yes" or response == "Yes")
{
break;
}
else
{
std::cout << "\nPlease only input yes or no: ";
std::cin >> response;
// Clear input
std::cin.clear();
std::cin.ignore(32767, '\n');
}
}
Full code:
#include <iostream>
#include <string>
#include <vector>
int main() {
bool exit = false;
//Open
std::cout << "==========\n";
std::cout << "WHALE TALK\n";
std::cout << "==========\n";
std::cout << "\n";
//main loop
while (!exit) {
//Variables
std::vector<char> whaletalk;
std::cout << "Type the text you want to translate to whale language: ";
//input
std::string input;
std::getline(std::cin, input);
std::cout << "\n\nWhale talk: ";
//vowels
std::vector <char> vowels = { 'a','e','i','o','u' };
//sorter
//iterating through string
for (int i = 0; i < input.size(); i++) {
//iterating through vowels
for (int j = 0; j < vowels.size(); j++) {
//case of vowels
if (input[i] == vowels[j]) {
//case of u and e
if ((input[i] == 'u') or (input[i] == 'e')) {
whaletalk.push_back(input[i]);
whaletalk.push_back(input[i]);
}
//case of vowels other than u and e
else { whaletalk.push_back(input[i]); }
}
}
}
//Output
for (int k = 0; k < whaletalk.size(); k++) {
std::cout << whaletalk[k];
}
std::cout << "\n";
// exit/no exit
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin >> response;
// Clear input
std::cin.clear();
std::cin.ignore(32767, '\n');
while (true) {
if (response == "NO" or response == "no" or response == "No") {
exit = true;
break;
}
else if (response == "YES" or response == "yes" or response == "Yes")
{
break;
}
else
{
std::cout << "\nPlease only input yes or no: ";
std::cin >> response;
// Clear input
std::cin.clear();
std::cin.ignore(32767, '\n');
}
}
}
return 0;
}

Unable to exit out of do-while loop?

I can't figure out why the do-while loop isn't being terminated upon user entering -1 in input. Just ignore everything after the internal while loop. I know that the problem is somewhere in the while loop. I just don't see it.
int main()
{
srand(time(0));
int input;
std::string pass, company, timeS;
do
{
std::cout << "Enter password length: ";
std::cin >> input;
while(input < 8 || input > 16)
{
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(100, '\n');
}
std::cout << "Password length must be between 8 and 16.\nEnter password length: ";
std::cin >> input;
}
std::cout << "Enter company name: ";
std::getline(std::cin, company);
pass = passGen(input);
time_t now = time(0);
auto time = *std::localtime(&now);
std::stringstream ss;
ss << std::put_time(&time, "%Y %b %d %H:%M:%S %a");
timeS = ss.str();
std::cout << "You passoword: " << pass << std::endl;
writeFile(pass, company, timeS);
}while(input != -1);
return 0;
}
Thanks in advance!
In this loop you wait for number between 8 and 16:
while(input < 8 || input > 16)
{
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(100, '\n');
}
std::cout << "Password length must be between 8 and 16.\nEnter password length: ";
std::cin >> input;
}
Guess, what never comes out of that loop? Right, -1 !! =)
Hope this will answer your question:
int main()
{
srand(time(0));
int input;
std::string pass, company, timeS;
// do
// {
while(true){
std::cout << "Enter password length: ";
std::cin >> input;
if(input == -1){
break;
}
while(input < 8 || input > 16)
{
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(100, '\n');
}
std::cout<< "=====>>>" << std::endl;
std::cout << "Password length must be between 8 and 16.\nEnter password length: ";
std::cin >> input;
}
std::cout << "Enter company name: ";
std::getline(std::cin, company);
pass = passGen(input);
time_t now = time(0);
auto time = *std::localtime(&now);
std::stringstream ss;
ss << std::put_time(&time, "%Y %b %d %H:%M:%S %a");
timeS = ss.str();
std::cout << "You passoword: " << pass << std::endl;
writeFile(pass, company, timeS);
}
// }while(input != -1);
return 0;
}
Just use
while(true){
//getting length of password
if(input == -1){
break;
}
//rest of the logic
}
The internal while loop will never terminate as the condition is will always be true for -1.
int main()
{
srand(time(0));
int input;
std::string pass, company, timeS;
do
{
std::cout << "Enter password length: ";
std::cin >> input;
while((input < 8 && input>=0)|| input > 16)
{
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(100, '\n');
}
std::cout << "Password length must be between 8 and 16.\nEnter password length: ";
std::cin >> input;
}
if (input>0){
std::cout << "Enter company name: ";
std::getline(std::cin, company);
pass = passGen(input);
time_t now = time(0);
auto time = *std::localtime(&now);
std::stringstream ss;
ss << std::put_time(&time, "%Y %b %d %H:%M:%S %a");
timeS = ss.str();
std::cout << "You passoword: " << pass << std::endl;
writeFile(pass, company, timeS);
}
}while(input != -1);
return 0;
}
Just ignore everything after the internal while loop.
Ok. Let's do that...
int main()
{
int input;
do
{
std::cout << "Enter password length: ";
std::cin >> input;
while(input < 8 || input > 16)
{
std::cin >> input;
}
}while(input != -1);
return 0;
}
I know that the problem is somewhere in the while loop. I just don't see it.
I hope you see it now. Your inner while ensures that input is never -1.
I think your current problem is a symptom of not structuring your code. Hence, to fix your code I propose to use functions:
void do_something(int input);
bool read_and_validate(int& input) {
input = 0;
while(input < 8 || input > 16) {
std::cin >> input;
if (input == -1) return false;
}
return true;
}
int main() {
int input;
while( read_and_validate(input) ) {
do_something(input);
}
}

Why do I need to input a non-char value twice to end the program

I have some code that asks the user to enter an alphanumeric char, and if they enter something else (eg. #,#,$) it will ask again to enter an alphanumeric char.
For some reason I need to enter a non-alphanumeric character twice before it will accept it. Here is the code.
#include <iostream>
#include <cctype>
using namespace std;
void get_option(char& input, string msg) {
string clear_input;
bool isletter;
bool isnumber;
bool test = 0;
while (test == 0) {
cout << msg;
cin >> input;
isletter = isalpha(input);
isnumber = isdigit(input);
if (isletter == 0 && isnumber == 0) {
cin.clear();
cin >> clear_input;
cout << input << endl << isnumber << endl << isletter << endl;
test = 0;
}
else if (isletter == 1 || isnumber == 1) {
test = 1;
}
}
}
int main() {
char input;
string msg = "Please enter an alphanumeric char: ";
get_option(input, msg);
return 0;
}
It's because of the line cin >> clear_input;, for which I see absolutely no purpose. Remove that line (and the declaration of clear_input as for that matter).

C++ user input restriction with proper retry without "goto"

I have the following code:
qstn:
cout << "Input customer's lastname: ";
getline(cin, lname);
if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != string::npos) {
cout << "You can only input alpha here!\n";
cin.clear();
goto qstn;
} else if (lname.empty()) {
cout << "Please enter your firstname!\n";
cin.clear();
goto qstn;
}
int lnamel = lname.length();
int strl = str.length();
int is = 0;
for (int i = 1; i < strl;) {
i++;
is++;
if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ') {
cin.clear();
cout << "Please input your lastname properly!\n";
goto qstn;
}
}
// next question here
I'm having a hard time on thinking what will be the proper logic to avoid the
goto statement, since I was college I was using it but someone here said that
it's not good to use it at all cause it might ruin my code.
I tried using the do while loop but it's not smooth as goto.
Please help!
Here's an idiom I like to use:
int i;
if (std::cin >> prompt("enter an integer: ", i))
{
std::cout << "Read user input: " << i << "\n";
} else {
std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
}
Here, prompt is a smart input manipulator, that takes care of handling parse errors or stream failures and retrying.
It's quite generic so actually do many things, but you don't need to indicate all the options. When the manipulator is inserted into the stream it relays to the do_manip member:
template <typename Char, typename CharT>
friend std::basic_istream<Char, CharT>& operator>>(std::basic_istream<Char, CharT>& is, checked_input<T, Prompter>& manip) {
return manip.do_manip(is);
}
The do_manip handles all the logic without any gotos :) :
std::istream& do_manip(std::istream& is) {
auto attempt = [this] { return infinite() || retries_ > 0; };
while (attempt()) {
if (!infinite())
retries_ -= 1;
prompter_(out_);
if (is >> value_) {
if (!run_validators(out_))
is.setstate(is.rdstate() | std::ios::failbit);
else
break;
} else {
out_.get() << format_error_ << "\n";
}
if (attempt()) {
is.clear();
if (flush_on_error_)
is.ignore(1024, '\n');
}
}
return is;
}
You can see that there is a possibility to have validations run before accepting the input.
Here's a somewhat full-blown demo:
Live On Coliru
int main() {
using namespace inputmagic;
int i;
if (std::cin >> prompt("enter an integer: ", i)
.retries(3)
.flush_on_error(false)
.format_error("I couldn't read that (Numbers look like 123)")
.output(std::cerr)
.validate([](int v) { return v > 3 && v < 88; }, "value not in range (3,88)")
.validate([](int v) { return 0 == v % 2; })
.validate([](int v) { return v != 42; }, "The Answer Is Forbidden")
.multiple_diagnostics())
{
std::cout << "Read user input: " << i << "\n";
} else {
std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
}
}
You can see it will only accept valid integers
that are >3 and <88,
that are even
except 42 (forbidden number)
When entering the numbers 21, 42 and 10 on subsequent retries, you get: live
enter an integer: 21
Value not valid
enter an integer: 42
The Answer Is Forbidden
enter an integer: 10
Read user input: 10
However, if you enter 1 all the time you get this: live
enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
Input failed (too many attempts). Eof? false
Or if you read from a single line file: live
enter an integer: value not in range (3,88)
Value not valid
enter an integer: I couldn't read that (Numbers look like 123)
enter an integer: I couldn't read that (Numbers look like 123)
Input failed (too many attempts). Eof? true
Use a function:
bool getLastName(string & lname,
string & str)
{
cout << "Input customer's lastname: ";
getline(cin, lname);
if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")
!= string::npos)
{
cout << "You can only input alpha here!\n";
cin.clear();
return false;
}
else if (lname.empty())
{
cout << "Please enter your firstname!\n";
cin.clear();
return false;
}
int lnamel = lname.length();
int strl = str.length();
int is = 0;
for (int i = 1; i < strl;)
{
i++;
is++;
if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ')
{
cin.clear();
cout << "Please input your lastname properly!\n";
return false;
}
}
return true;
}
All I've done here is replace the gotos with return false. If the program makes it to the end of the function, return true. Make the function call in a while loop:
while (!getLastName(lname, str))
{
// do nothing
}
Not only does this de-spaghettify the code, but it breaks it up into nice, small, easy to manage pieces. This is called procedural programming.
A While loop looks like your best bet. You can redo the loop with the continue keyword.
int incorrect = 0;
while(!incorrect) {
cout<<"Input customer's lastname: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
continue;
}
else if(lname.empty())
{
cout<<"Please enter your firstname!\n";
cin.clear();
continue;
}
int lnamel=lname.length();
int strl=str.length();
int is=0;
for(int i=1; i<strl;)
{
i++;
is++;
if(lname[i]==lname[is]&&lname[i]==' '||lname[0]==' ')
{
cin.clear();
cout<<"Please input your lastname properly!\n";
continue;
}
incorrect = 1;
}
You need to use some do while loops
for instance this:
qstn:
cout<<"Input customer's lastname: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
goto qstn;
}
else if(lname.empty())
{
cout<<"Please enter your firstname!\n";
cin.clear();
goto qstn;
}
could be re-written as this:
int flag;
do{
flag = 1;
cout<<"Input customer's lastname: ";
getline(cin,lname);
if(lname.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
{
flag = 0;
cout<<"You can only input alpha here!\n";
}
else if(lname.empty())
{
flag = 0;
cout<<"Please enter your firstname!\n";
}
cin.clear();
} while( flag !=1 );
feel free to use a boolean type flag, it doesn't really matter
It seems to me that your code suffers from lack of clarity of purpose.
You apparently don't want the string that's entered to include a leading space, nor multiple consecutive spaces. Other than that, only alphabetic characters should be accepted.
If the user does enter multiple consecutive spaces, I'd probably just ignore all but the first. I'd probably write the code something like this:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <sstream>
bool non_alpha(std::string const &s) {
return !std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalpha(c) || std::isspace(c); });
}
std::string get_name(std::string const &prompt) {
std::string result;
std::string line;
do {
std::cout << prompt;
std::getline(std::cin, line);
} while (non_alpha(line));
std::istringstream words(line);
std::string word;
while (words >> word)
result += word + ' ';
return result;
}
int main() {
auto res = get_name("Please enter last name, alpha-only\n");
if (res.empty())
std::cout << "Oh well, maybe some other time";
else
std::cout << "Thanks Mr(s). " << res << "\n";
}
I'd be tempted to consider doing roughly the same for non-alphabetic characters--rather than asking the user to re-enter from the beginning, assume it's a mistake and just ignore it.

Double Line when user is asked to press i to view Inventory

Hey Basically i have 2 functions:
void Inventory:: showInventory()
{
char input[80];
cin >> input;
char inventoryRequest[] = "i";
//compare the player input to inventoryRequest (i) to see if they want to
//look at inventory.
int invent = strcmp (input,inventoryRequest);
if(invent == 0) {
//vector<string> inventory;
cout << "You have " << inventory.size() << " items.\n";
cout << "\n******Inventory******";
cout << "\nYour items:\n";
for (int i= 0; i< inventory.size(); ++i) {
cout<< inventory[i] << endl;
}
}
}
void Inventory :: displayInventory(const string str) {
char input = 0;
do
{
cout << str << endl;
cin >> input;
}
while((input != 'i') && (input != 'I') && (input != 'n') && (input != 'N'));
showInventory();
//return input;
}
showInventory compares the player input to i.
display inventory only lets the user press i or n.
i to view the inventory and n to skip.
But when i is pressed. It causes a double line.
Meaning i has to be pressed twice to view the inventory.
I have tried numerous things to stop this from occuring. But i have not succeeded and most of the time the inventory cannot be viewed at all.
Can anybody help me with this.
Thanks in advance.
Try using a parameter for input on void Inventory::showInventory(), and eliminating the second cin, something like this:
void Inventory:: showInventory(char input)
{
//char input[80];
//cin >> input;
//char inventoryRequest[] = "i";
//int invent = strcmp (input,inventoryRequest);
//compare the player input to inventoryRequest (i) to see if they want to look at inventory.
//if(invent == 0) // REPLACE THIS WITH THE LINE BELOW
if(input == 'i')
And then when you call it, do it like this:
showInventory(input);