Definition of the Valid Input
Here I assume that the valid input is given by the following natural statements. First of all, as you mentioned,
Each input must be constructed from *
, /
, %
, +
and an integer.
Only zero or one operation. ( So 1+1
is valid. )
For an input of an integer, I also assume
Whitespace characters are allowed in the left and right side of the input string.
Whitespace characters between non-whitespace characters are not allowed.
The first non-whitespace character must be 0
, 1
, ..., 9
or -
(for negative integers).
The second and the subsequent non-whitespace characters must be 0
, 1
, ..., 8
or 9
.
Note that in my assumption the positive sign character +
, decimal-point character .
are not allowed for integer inputs.
For instance, in this definition,
"123"
, " 123"
, "123 "
and " -123 "
are all valid integer inputs.
"abc"
, "123a"
, " 1 23"
, "+123"
and "1.0"
are all invalid ones.
Validity Check Function for An Integer
First, to check the validity of the input of an integer, we trim the input and remove left and right whitespaces using the following trimming function: ( If you can use C++17, std::string_view
would be more preferable from the performance poin of view.)
#include <string>
std::string trimLR(const std::string& str)
{
const auto strBegin = str.find_first_not_of(" \f\n\r\t\v");
if (strBegin == std::string::npos){
return "";
}
const auto strEnd = str.find_last_not_of(" \f\n\r\t\v");
const auto strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
Next, we define the following simple validity check function isInteger
which checks whether the passed string is an integer or not. Here std::isdigit
is useful to check whether each character is digits or not.
Please note that various interesting methods are proposed in the past
posts.
#include <string>
#include <algorithm>
bool isInteger(const std::string& s)
{
const auto ts = trimLR(s);
if(ts.empty()){
return false;
}
const std::size_t offset = (ts[0] == '-') ? 1 : 0;
const auto begin = ts.cbegin() + offset;
return (begin != ts.cend()) // false if s is just a negative sign "-"
&& std::all_of(begin, ts.cend(), [](unsigned char c){
return std::isdigit(c);
});
}
Main Function
Now it is easy and straightforward to implement the main function.
The following code will check inputs and work fine.
The next considerations are writing tests and performance tunings:
DEMO(Multiplication)
DEMO(Division)
DEMO(Modulo)
DEMO(Addition)
DEMO(Invalid 1)
DEMO(Invalid 2)
#include <iostream>
int main()
{
std::string x;
std::cout << "Enter expression: ";
std::getline(std::cin, x);
const auto optPos = x.find_first_of("*/%+");
if (optPos == std::string::npos)
{
if(isInteger(x)){
std::cout << "Valid input, " << x;
}
else{
std::cout << "Invalid input, " << x;
}
return 0;
}
const auto left = x.substr(0, optPos);
const auto opt = x.substr(optPos, 1);
const auto right = x.substr(std::min(optPos+1, x.length()-1));
if (!isInteger(left) || !isInteger(right))
{
std::cout
<< "Either `" << left << "`, `" << right
<< "` or both are invalid inputs." << std::endl;
return 0;
}
const auto leftVal = std::stod(left);
const auto rightVal = std::stod(right);
if(opt == "*")
{
std::cout
<< "Multiplication: "
<< x << " = " << (leftVal * rightVal);
}
else if(opt == "/")
{
std::cout
<< "Division: "
<< x << " = " << (leftVal / rightVal);
}
else if(opt == "%")
{
std::cout
<< "Modulo: "
<< x << " = " << (std::stoi(left) % std::stoi(right));
}
else if(opt == "+")
{
std::cout
<< "Addition: "
<< x << " = " << (leftVal + rightVal);
}
return 0;
}