Reading input commands with up to 3 commands - c++

I have a program which prompts the user to input a command. Based on the command, it will perform different functions.
example commands:
help
set value 20
set another 30
print this
print that
How can I split these into 3 separate variables and continue the program? I'm having trouble with a simple
string command;
string item;
string value;
cin >> command >> item >> value;
Because unless the user inputs all three, the program won't continue.
This is what I came up with, I can't answer my own question so this will do.
Thank you for the input. This is what I came up with after researching some of those functions mentioned by #JoachimPileborg. It seems to work just how I need it.
int main() {
bool done = false;
char input[30];
std::string command, item, value;
//output instructions, get user input
std::cout << "Type 'help' to find more about commands.\n";
do{
std::cin.getline(input,30);
//parse user input from char to an array
istringstream iss;
string commands[3];
iss.str (input);
for (int i = 0; i < 3; i++) {
iss >> commands[i];
}
//set each part of the array to appropriate value
command = commands[0];
item = commands[1];
value = commands[2];
//properly sort out which command is being called
//first: check if command has 3 parts
if (commands[2].length() != 0){
cout << command << item << value;
}
//second:if it doesnt have 3 parts, check if it has 2 parts
else if (commands[1].length() != 0){
cout << command << item;
}
//third:if it doesn't have 2 parts, check for 1 part
else if (commands[0].length() != 0){
if (command == "help"){
commandline.help();
done = true;
}
else{
cout << "Incorrect Command! Please try again!";
}
}
else
cout << "No command found, please try again!";
}while(!done);
}

"How can I split these into 3 separate variables and continue the program?"
Don't have distinct variables, use an appropriate standard library container to collect a variable number of parameters given for a command.
The very simplest way,- I can imagine -, how to implement such thing, would probably look like this:
std::string cmdline;
while(cmdline != "quit") {
std::cout << "Enter command > ";
std::getline(std::cin),cmdline);
if(!cmdline.empty()) {
std::istringstream iss(cmdline);
std::vector<std::string> cmditems;
std::string cmditem;
while(iss >> cmditem) {
cmditems.push_back(cmditem);
}
if(cmditems.empty()) { // Just whitespaces input
continue;
}
// accessing cmditems[0] is always safe at this point
if(cmditems[0] == "help") {
printHelp();
}
else if(cmditems[0] == "set") {
// Check if the number of command arguments actually
// fit the required ones
if(cmditems.size() < 3) {
std::cerr << "Please enter a name and value!" << std::endl;
continue;
}
setValue(cmditems[1],cmditems[2]);
}
else if(cmditems[0] == "print") {
// Check if the number of command arguments actually
// fit the required ones
if(cmditems.size() < 2) {
std::cerr << "Please enter a name to print!" << std::endl;
continue;
}
printValue(cmditems[1]);
}
// and so on ...
}
}

Related

C++ Two user input keywords in the same line plus separate checking

I've been trying to get an if statement to work with two key words. Basically my program will check the first word as the "command" word (like get, set, etc), the one that will trigger the specific method, and the second word as the one to search in a list, as an object to use. They must be both writen together in the same line.
I know getline can input several words and cin >> this >> that also does it. But for separate checking I can't be able to figure it out.
I was advised substrings, but not sure how to do that.
Example:
First word as the command, other as the key to search.
if(command == "kick")
{
std::cin >> input; //user input "ball"
person->kick(input) //pointer to function in another class
***kicks the ball
}
if(command == "pick")
{
std::cin >> input; //user input "ball"
person->pick(input) //pointer to function in another class
***picks the ball
}
if(command == "throw")
{
std::cin >> input; //user input "paper"
person->throw(input) //pointer to function in another class
***throws the paper
}
It works, but my input is supposed:
kick ball or
pick ball
instead of
kick
ball
and so on.
It's probably super simple, I'm just new to c++.
It must be in the same line of input though, otherwise there would probably be better ways.
Would love some help.
Thanks ;)
If I understand that you need to take both the cmd and key as separate inputs, but the user will enter the string "cmd key" and you need to handle each individually, then a simple method is to read each into a std:string using the normal >> operator, e.g.
std::string cmd, key;
std::cout << "enter command & key: ";
if (!(std::cin >> cmd >> key)) { /* read/validate both cmd & key */
std::cerr << "stream error or use canceled input.\n";
return 1;
}
Now you have both cmd and key stored and can use cmd to initially determine what branch to take and then select what action to take based on key. For example:
if (cmd == "kick") { /* handle cmd "kick" */
if (key == "ball")
std::cout << "kicking the ball.\n";
else if (key == "dog")
std::cout << "kicking the dog.\n";
else
std::cout << "generally kicking the " << key << ".\n";
}
else if (cmd == "pick") { /* handle cmd "pick" */
if (key == "ball")
std::cout << "picking the ball.\n";
else if (key == "dog")
std::cout << "picking the dog.\n";
else
std::cout << "generally picking the " << key << ".\n";
}
else /* otherwise unknown command */
std::cout << "unknown cmd: " << cmd << ".\n";
(note: you always want to handle the case the user has entered something invalid for each cmd or key (or both))
Putting it together in a short example, you could do:
#include <iostream>
#include <string>
int main (void) {
std::string cmd, key;
std::cout << "enter command & key: ";
if (!(std::cin >> cmd >> key)) { /* read/validate both cmd & key */
std::cerr << "stream error or use canceled input.\n";
return 1;
}
if (cmd == "kick") { /* handle cmd "kick" */
if (key == "ball")
std::cout << "kicking the ball.\n";
else if (key == "dog")
std::cout << "kicking the dog.\n";
else
std::cout << "generally kicking the " << key << ".\n";
}
else if (cmd == "pick") { /* handle cmd "pick" */
if (key == "ball")
std::cout << "picking the ball.\n";
else if (key == "dog")
std::cout << "picking the dog.\n";
else
std::cout << "generally picking the " << key << ".\n";
}
else /* otherwise unknown command */
std::cout << "unknown cmd: " << cmd << ".\n";
}
Example Use/Output
$ ./bin/cmd_select
enter command & key: kick dog
kicking the dog.
With command "pick":
$ ./bin/cmd_select
enter command & key: pick ball
picking the ball.
With unknown command:
$ ./bin/cmd_select
enter command & key: shoot dog
unknown cmd: shoot.
You can of course pass the string for cmd or key to a separate function and handle your response to each there, but that is just another way of arranging your code to do the same thing. Look things over and let me know if this is what you were intending. I'm still not 100% clear based on the many edits.

C++ - cin to only take one integer

This code works fine if I enter something that isn't a number in, e.g. F: it will print the error message. However, if I enter e.g. 2F2 or , it will take the 2 and pass the check, continue in my code and on the next cin >> statement it will put the F in, and then it loops back and puts the 2 in.
How do I make it so it only accepts a single number e.g. 2 and not e.g. 2F2 or 2.2?
int bet = 0;
// User input for bet
cout << " Place your bet: ";
cin >> bet;
cout <<
// Check if the bet is a number
if (!cin.good())
{
cin.clear();
cin.ignore();
cout << endl << "Please enter a valid number" << endl;
return;
}
bool Checknum(std::string line) {
bool isnum = true;
int decimalpoint = 0;
for (unsigned int i = 0; i < line.length(); ++i) {
if (isdigit(line[i]) == false) {
if (line[i] == '.') {
++decimalpoint; // Checks if the input has a decimal point that is causing the error.
}
else {
isnum = false;
break;
}
}
}
if (decimalpoint > 1) // If it has more than one decimal point.
isnum = false;
return isnum;
}
If you take a string from the user, this should work. You can convert the string to an integer or a float(stoi or stof, respectively). It may not be the best solution there is, but this is what I have. Excuse the indentation.
Do getline to read one whole line of input from cin.
Create a stringstream to parse the string you got.
In this parser, read the number; if it fails - error
Read whitespace; if it doesn't arrive to the end of string - error
#include <sstream>
...
int bet = 0;
std::cout << " Place your bet: ";
while (true)
{
std::string temp_str;
std::getline(cin, temp_str);
std::stringstream parser(temp_str);
if (parser >> bet && (parser >> std::ws).eof())
break; // success
cout << endl << "Please enter a valid number" << endl;
}
This code keeps printing the error message until it receives valid input. Not sure this is exactly what you want, but it's pretty customary UI.
Here >> ws means "read all the whitespace". And eof ("end of file") means "end of the input string".

Check for Empty sstream

I am wrote a function that can replace cin for integers and potentially doubles, that includes error checking capabilities. Using cin.fail() I was able to check for most cases, but that didn't cover the case where the input was followed by a string without a space. For example, "23tewnty-three." The following code accommodates this.
int getUserInt(string prompt = "Enter an integer: ", string errorMessage "Error: Invalid Input") {
const int IGNORE_MAX = 100;
int userInt = 0;
bool isContinue = true;
do {
// initialize and reset variables
string inputStr;
istringstream inputCheck;
userInt = 0;
// get input
cout << prompt;
cin >> inputStr;
inputCheck.str(inputStr);
// check for valid input
inputCheck >> userInt;
if (!inputCheck.fail()) {
// check for remaining characters
if (inputCheck.eof()) { // Edit: This is the section that I tried replacing with different code (made code compilable in response to comment)
isContinue = false;
}
else {
cout << errorMessage << endl;
}
}
else {
// reset cin and print error message
cin.ignore(IGNORE_MAX, '\n');
cin.clear();
cout << errorMessage << endl;
}
} while (isContinue);
return userInt;
}
This code works, but the reason I am posting this to Stack Overflow instead of Code Review is because my main question is about why some of code didn't work as I expected. The following is what I tried in place of inputCheck.eof() in the previous code. My questions are what are the differences between the following code? Why didn't methods 2) and 3) work? and which method is preferred?
inputCheck.eof()
inputCheck.peek() == EOF
inputCheck.str().empty()
inputCheck.rdbuf()->in_avail() == 0
1) and 4) worked as expected, but 2) and 3) did not.
Edit:
I believe 3) didn't work as expected because inputCheck.str() returns what was contained in inputStr when inputCheck.str(inputStr) was called. However, I have no idea why inputCheck.peek() == EOF didn't work.
If this is relevant information, I am compiling and running on windows through bash g++.
For every prompt you provide, you can expect your user to press Enter. Obtain input as a string, then try to convert. (Don’t try to convert from cin.)
Bonus: here’s a function to perform conversion.
template <typename T>
auto string_to( const std::string & s )
{
T value;
std::istringstream ss( s );
return ((ss >> value) and (ss >> std::ws).eof())
? value
: std::optional<T> { };
}
You’ll need C++17 for that, or to #include <boost/optional.hpp> instead.
Now:
std::cout << "Enter an integer! ";
std::string s;
getline( std::cin, s );
auto x = string_to <int> ( s );
if (!x)
{
std::cout << "That was _not_ an integer.\n";
}
else
{
std::cout << "Good job. You entered the integer " << *x << ".\n";
}
No more worrying about clearing or resetting cin. Handily perform some loops (such as allow user three attempts before quitting). Et cetera.

How do I stop spaces from displaying as carriage returns when read in from a file?

void displayFile()
{
char userInput[20];//Used to store the typed input commands from the user.
ifstream ip("D:\\H Drive ITT\\Level 8 Degree\\Software Dev (Andrew)\\MiniProject\\about.txt");//Input from file
string line ;//Store each line in the string
int exit = 0;//Used to hold the value which indicates whether or not the function should end determined by the user.
if (ip)//ip is true if the file exists.
{}
else
{
cout << "-Error_File_Not_Found" << endl;
}
while (!ip.eof())//Scan till end of file
{
ip >> line;
cout << line << endl;
}
cout << "Type exit to return" << endl << endl << ">>>" ;
do {
cin >> userInput;
if (strcmp(userInput, "exit") == 0 || strcmp(userInput, "EXIT") == 0 || strcmp(userInput, "eXIT") == 0 || strcmp(userInput, "Exit") == 0)
{
exit = 1;
}
else
{
exit = 0;
}
} while (exit !=1);
ip.close();
}
//The
//output
//displays
//like
//this.
When the code runs it takes in the paragraph and displays each word on a line of its own. I have seen solutions that involve classes but I need a different solution as I have not done classes yet.
There are two problems here.
The >> operator does not read lines, it stops on whitespace. Use std::getline as Ramana suggested in the comments.
You are using eof() incorrectly. It returns true after you have already read past the end of the file, not before you would read past the end. So your loop will iterate one time too many. The best method is to use the return value of std::getline as the loop condition.

C++ user input restrictions

I'm currently working on a program and thinking if it is possible to implement another restrictions for the user input. The restrictions that I made as of now is that the user is only allow to input alpha and spaces, hitting enter without any input will not be also accepted.
cout<<"Input customer's lastname\t\t: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyz ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
goto p1;
}
else if(lname.empty())
{
cout<<"Please enter your lastname!\n";
cin.clear();
goto p1;
}
The another restrictions that I want is if the user input is all spaces, the program will also show a message. Second, I wonder if it's possible to detect the input if the user typed it properly like (de la Cruz) the words should be only separated by one space and if not another message will show. I cant think on how to do it, I already did some research but I couldn't found any similar to this with C++. I don't know if this is possible since I'm just starting to learn C++, or maybe I don't have enough logic at all. :(
A little help from me on checking for spaces.
bool has_only_spaces(const std::string& str)
{
return str.find_first_not_of (' ') == str.npos;
}
bool has_two_consecutive_spaces(const std::string& str)
{
for (unsigned int i = 1; i < str.length(); i++)
{
if ((str[i - 1] == str[i]) && (str[i] == ' '))
{
return true;
}
}
return false;
}
int main()
{
std::string lname;
std::cout << "Input customer's last name: ";
getline(std::cin, lname);
if (has_only_spaces(lname) || has_two_consecutive_spaces(lname))
{
std::cout << "Not a valid input" << std::endl;
std::cin.clear();
}
}
Create a function to check whether the input is valid. Use the function in a while loop.
bools isInputValid(std::string const& input)
{
// add all the checks
}
Use it as:
std::cout << "Enter input\n";
while ( getline(std::cout, line) )
{
if ( isInputValid(line) )
{
break;
}
std::cout << "Input is not vaild. Try again\n";
}