Accepting only numbers in the user input c++ - c++

Right now I am using this function to get the user input.
int getOnlyNumber(int num)
{
while (!(cin >> num)) {
// Reset the input:
cin.clear();
// Get rid of the bad input before return was pressed:
while (cin.get() != '\n')
{
continue;
}
// Ask user to try again:
cout << "Please enter a number: ";
}
return num;
}
This seems to only catch bad input if the letter is entered first. If a number is entered first, the program accepts it. Ex. it will accept 1e but will catch e1.
This is being used like this:
displayChoice = getOnlyNumber(displayChoice);
Where displayChoice is an int.
What do i need to change to catch 1e as a input or any other input that starts with a number but has strings?

If you give it a partial number then, by default, it does the best it can and gives you the bits it did manage to understand.
If you want to see if there was an error during the conversion then you have to check cin.fail().
while (!(cin >> num) || cin.get()!='\n') {
...

You can use std::all_of to test if an entire string is a number:
std::string str;
auto is_digit_check = [] (unsigned char c) { return std::isdigit(c); };
while (!(std::cin >> str) ||
!std::all_of(str.begin(), str.end(), is_digit_check))
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return std::stoi(str);

Related

How can I make my else statement account for anything that isn't an integer? [duplicate]

Currently having issues creating an integer validation loop in my code.
Trying to validate for an integer, however this code fails to work if you input, for example the string '22a' it sets trial_no as 22. Is there any way to check that every charachter input is indeed a string, such that '22a' or '2a2' would be considered erroneous and the loop would continue until a valid integer was input?
int trial_no;
bool valid = false;
while(!valid)
{
valid = true; //assume trial_no will be an integer
cout << "Enter the number of die throws to simulate" << endl;
cin >> trial_no;
if(cin.fail()) // exit loop condition is dependent on trail_no being a valid integer
{
cin.clear(); //corrects stream
cin.ignore(numeric_limits<streamsize>::max(), '\n'); //skips left over stream data (numeric_limit
// is in case user enters more than one letter))
cout << "Please enter an integer value" << endl;
valid = false; //cin not an integer so loop goes round to try again
}
}
Arguably the best way is to read the entire line as a string and utilize the std::stoi function:
#include <iostream>
#include <string>
int main() {
std::cout << "Enter an integer: ";
std::string tempstr;
bool valid = false;
std::getline(std::cin, tempstr);
try {
int result = std::stoi(tempstr);
std::cout << "The result is: " << result;
valid = true;
}
catch (std::invalid_argument) {
std::cout << "Could not convert to integer.";
valid = false;
}
}
As pointed out in the comments, this function can also throw a std::out_of_range exception. This assumes your compiler is C++11 (+) capable. If not, go down the std::stringstream route:
std::string tempstr;
std::getline(std::cin, tempstr);
std::stringstream ss(tempstr);
int result;
bool valid = false;
if (ss >> result) {
valid = true;
}
else {
valid = false;
}

Ending an input stream with a specified character, such as '|'?

Currently learning C++, newbie.
I have an issue when ending the input with the '|' character, my program skips to the end/ends and does not allow for further input. I believe it is because std::cin is in an error state due to inputting a char when expecting an int, so i have tried to use std::cin.clear() and std::cin.ignore() to clear the issue and allow the remainder of the programme to run but I still cannot seem to crack it, any advice appreciated.
int main()
{
std::vector<int> numbers{};
int input{};
char endWith{ '|' };
std::cout << "please enter some integers and press " << endWith << " to stop!\n";
while (std::cin >> input)
{
if (std::cin >> input)
{
numbers.push_back(input);
}
else
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
}
}
And then pass the vector to a function to iterate through x amount of times and add each element to a total, but the program always skips past the user input:
std::cout << "Enter the amount of integers you want to sum!\n";
int x{};
int total{};
std::cin >> x;
for (int i{ 0 }; i < x; ++i)
{
total += print[i];
}
std::cout << "The total of the first " << x << " numbers is " << total;
Please help!
When the use enters a "|" (or anything that is not an int), the loop ends and the error handling that is inside the loop does not execute. Just move the error code to outside the loop. Also, you read from stdin twice which will skip every other int.
while (std::cin >> input) {
numbers.push_back(input);
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Note: If you want to specifically check for "|" can change to something like this:
while (true) {
if (std::cin >> input) {
numbers.push_back(input);
}
else {
// Clear error state
std::cin.clear();
char c;
// Read single char
std::cin >> c;
if (c == '|') break;
// else what to do if it is not an int or "|"??
}
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

C++ Integer Followed by char gets accepted as an input

I am using a function to check that my input in an integer only:
int input;
while (true)
{
std::cin >> input;
if (!std::cin)
{
std::cout << "Bad Format. Please Insert an integer! " << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
else
return input;
}
However when inputing a integer followed by a char, eg. 3s, the integer gets accepted and the message gets printed.
How can I make sure that the input in such format does not get accepted, nor do input in form 4s 5, so when the integer appears after the space.
That happens because chars in c++ are represented by their numeric value in the ascii table, you can try regular expressions like this:
#include <regex>
#include <string>
std::string str;
std::regex regex_int("-?[0-9]");
while (true)
{
std::cin >> str;
if (regex_match(str, regex_int))
{
int num = std::stoi(str);
//do sth
break;
}
}
There's no need for a regular expression that duplicates the validation that std::stoi does. Just use std::stoi:
std::string input;
std::cin >> input;
std::size_t end;
int result = std::stoi(input, &end);
if (end != input.size())
// error

Validating input and getline() function

So I want to validate the user only enters text and not numbers. If any number is input, then I ask her again for input. I thought this would do the trick, but it doesn't seem to work:
#include <iostream>
using namespace std;
int main()
{
string name = "";
cout << "Enter name: ";
getline(cin, name);
while (!cin) // or cin.fail()
{
cout << "Numbers are not allowed, input name again: ";
cin.clear();
cin.ignore(1000, '\n'); // is this even necessary since getline() already consumes spaces and new lines?
getline(cin, name);
}
}
Because the name variable is of string type, shouldn't the cin object fail when it receives a number? How can I validate it and make sure it prompts for input again when a number is entered? Also, out of curiosity since I'm asking already, if the user enters something like: Scarlett9356, what would be a good way to re-prompt for good input? Thank you.
You could validate that there are no numbers in your string by doing this:
#include <iostream>
using namespace std;
bool validName(string name)
{
if(name.length() == 0)
return false; // `name` cannot be empty
for(int i = 0; i < name.length(); i++)
if(name[i] >= '0' && name[i] <= '9')
return false; // There is a number in `name`
return true; // `name` is valid
}
int main()
{
string name = "";
cout << "Enter name: ";
getline(cin, name);
while (!validName(name))
{
cout << "Numbers are not allowed, input name again: ";
cin.clear();
cin.ignore(1000, '\n'); // is this even necessary since getline() already consumes spaces and new lines?
getline(cin, name);
}
}
Because the name variable is of string type, shouldn't the cin object fail when it receives a number?
No. Input that consists of digits is valid as string also.
You'll need to use a different strategy for making that an invalid input.
I would suggest something along the lines of:
bool is_valid_input(std::string const& name)
{
bool is_valid = true;
// Figure out the logic for deciding when the input is not valid.
// ...
if (!is_valid )
{
cout << "Numbers are not allowed, input name again: ";
}
return is_valid;
}
int main()
{
string name = "";
do
{
cout << "Enter name: ";
getline(cin, name);
}
while ( !is_valid_input(name) );
}
If you want to limit your input to only taking in string without a number in it then you can use std::any_of and std::isdigit
std::string name = "";
std::cout << "Enter name: ";
std::getline(std::cin, name);
while (std::any_of(name.begin(), name.end(), [](char ch) { return std::isdigit(ch); }))
{
std::cout << "Numbers are not allowed, input name again: ";
std::getline(std::cin, name);
}

C++ - Sanitize Integer Whole Number Input

I currently am using a function I found in another StackOverflow post(I can't find it), that I am using before, named "GetInt". My issue with it is that if the user inputs something like "2 2 2" it puts it into my next two Cin's. I have tried getLine, but it requires a string and I am looking for an int value. How would I structure a check to sanitize for an integer value greater than 2 and throw an error to the 2 2 2 answer.
#include <iostream>
#include <string>
#include <sstream>
#include "Board.cpp"
#include "Player.cpp"
using namespace std;
int getInt()
{
int x = 0;
while (!( cin >> x))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please input a proper 'whole' number: " << endl;
}
return (x);
}
and my call
do
{
//do
//{
cout << "How many players are there? \n";
numberOfPlayers = getInt();
//} while (isdigit(numberOfPlayers) == false);
} while (numberOfPlayers < 2);
EDIT:
I chose Justin's answer because it was the closest to my original code and solved the issue without major changes.
Integers are delimited by spaces and the input 2 2 2 is just multiple integers. If you want to make sure that just one integer is entered per line you could skip whitespace characters until a newline is found. If a non-whitespace is found prior to a newline you could issue an error:
numberOfPlayers = getInt();
int c;
while (std::isspace(c = std::cin.peek()) && c != '\n') {
std::cin.ignore();
}
if (c != std::char_traits<char>::eof() && c != '\n') {
// deal with additional input on the same line here
}
You were on the right track with std::getline. You read the whole line as a string, then put it into a std::istringstream and read the integer out.
std::string line;
if( std::getline(cin, line) ) {
std::istringstream iss(line);
int x;
if( iss >> x ) return x;
}
// Error
This will have the effect of discarding any fluff that comes after the integer. It will only error if there is no input or no integer could be read.
If you want to have an error when stuff appears after the integer, you could take advantage of the way strings are read from a stream. Any whitespace is okay, but anything else is an error:
std::istringstream iss(line);
int x;
if( iss >> x ) {
std::string fluff;
if( iss >> fluff ) {
// Error
} else {
return x;
}
}
Change your code to this:
int getInt()
{
int x = 0;
while (!( cin >> x))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please input a proper 'whole' number: " << endl;
}
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return (x);
}
Your code to ignore the rest of the line after receiving the integer is only called if the integer collection fails (for example, you type "h" as the number of players).