In a C++ program I'm trying to process user input which consists of integer operands interspersed with operators (+ - / *). I have the luxury of requiring users to put whitespace(s) before and after each operator. My approach is to assume that anything that's not an int is an operator. So as soon as there's a non eof error on the stream, I call cin.clear() and read the next value into a string.
#include <iostream>
#include <string>
//in some other .cpp i have these functions defined
void process_operand(int);
void process_operator(string);
using namespace std;
int main()
{
int oprnd;
string oprtr;
for (;; )
{
while ( cin >> oprnd)
process_operand(oprnd);
if (cin.eof())
break;
cin.clear();
cin >> oprtr;
process_operator(oprtr);
}
}
This works fine for / and * operators but not for + - operators. The reason is that operator>> eats away the + or - before reporting the error and doesn't put it back on the stream. So I get an invalid token read into oprtr.
Ex: 5 1 * 2 4 6 * / works fine
5 1 + 2
^ ---> 2 becomes the oprnd here.
What would be a good C++ way of dealing with this problem?
Read in std::strings and convert them using boost::lexical_cast<> or its equivalent.
int main()
{
string token;
while ( cin >> token) {
try {
process_operand(boost::lexical_cast<int>(token));
} catch (std::bad_cast& e) {
process_operator(token);
}
}
}
Postscript: If you are allergic to Boost, you can use this implementation of lexical_cast:
template <class T, class U>
T lexical_cast(const U& u) {
T t;
std::stringstream s;
s << u;
s >> t;
if( !s )
throw std::bad_cast();
if( s.get() != std::stringstream::traits_type::eof() )
throw std::bad_cast();
return t;
}
I think >> thinks you are starting another integer with +/-. Then gets mad when you don't follow with digits.
As #Robᵩ said, read a string and cast. I would only offer another choice from the standard library:
int stoi(const string& str, size_t *idx = 0, int base = 10);
This throws invalid_argument if no conversion could be performed or out_of_range if the converted value is outside the range of representable values for the return type.
This is from The Standard.
Related
in C++ I am creating a program that asks a user for a date in the following format: MM/DD/YYYY. Since the date is an int and must be an int, I figured the most logical way to get this in one line is if I was to use an array.
So I created something like this...
int dateArray[3];
for (int i=0; i<3; i++)
cin >> dateArray[i];
int month = dateArray[0];
...etc
My question is if a user enters "1/23/1980" is there a way I can ignore the / that the user inputs?
Thank you.
You can ignore one character using std::istream::ignore(). Since you probably only want to ignore intervening characters, you'd need to know when to ignore and when not to ignore. For a date I would personally not bother but just read the three terms:
if (((std::cin >> month).ignore() >> year).ignore() >> day) {
// do something with the date
}
else {
// deal with input errors
}
I would actually also be inclined to check that the correct separator is received and probably just create a manipulator for this purpose:
std::istream& slash(std::istream& in) {
if ((in >> std::ws).peek() != '/') {
in.setstate(std::ios_base::failbit);
}
else {
in.ignore();
}
return in;
}
// ....
if (std::cin >> month >> slash >> year >> slash >> day) {
// ...
}
... and, obviously, I would check in all cases that the input is correct.
Consider using C++11 regular expression library support for this type of parsing. For instance
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
int main()
{
std::string string{ "12/34/5678" };
std::regex regex{ R"((\d{2})/(\d{2})/(\d{4}))" };
auto regexIterator = std::sregex_iterator( std::begin( string ), std::end( string ), regex );
std::vector< std::string > mdy;
for( auto matchItor = regexIterator; matchItor != std::sregex_iterator{}; ++matchItor )
{
std::smatch match{ *matchItor };
mdy.push_back( match.str() );
}
const std::size_t mdySize{ mdy.size() };
for( std::size_t matchIndex{ 0 }; matchIndex < mdySize; ++matchIndex )
{
if( matchIndex != mdySize && matchIndex != 0 ) std::cout << '/';
std::cout << mdy.at( matchIndex );
}
}
I would not ignore it; it's part of your format, even though you do not need to keep it around indefinitely.
I would read it into a char and make sure that it is, in fact, a /.
I have this piece of code :
if(flag == 0)
{
// converting string value to integer
istringstream(temp) >> value ;
value = (int) value ; // value is a
}
I am not sure if I am using the istringstream operator right . I want to convert the variable "value" to integer.
Compiler error : Invalid use of istringstream.
How should I fix it ?
After trying to fix with the first given answer . it's showing me the following error :
stoi was not declared in this scope
Is there a way we can work past it . The code i am using right now is :
int i = 0 ;
while(temp[i] != '\0')
{
if(temp[i] == '.')
{
flag = 1;
double value = stod(temp);
}
i++ ;
}
if(flag == 0)
{
// converting string value to integer
int value = stoi(temp) ;
}
Unless you really need to do otherwise, consider just using something like:
int value = std::stoi(temp);
If you must use a stringstream, you typically want to use it wrapped in a lexical_cast function:
int value = lexical_cast<int>(temp);
The code for that looks something like:
template <class T, class U>
T lexical_cast(U const &input) {
std::istringstream buffer(input);
T result;
buffer >> result;
return result;
}
As to how to imitation stoi if your don't have one, I'd use strtol as the starting point:
int stoi(const string &s, size_t *end = NULL, int base = 10) {
return static_cast<int>(strtol(s.c_str(), end, base);
}
Note that this is pretty much a quick and dirty imitation that doesn't really fulfill the requirements of stoi correctly at all. For example, it should really throw an exception if the input couldn't be converted at all (e.g., passing letters in base 10).
For double you can implement stod about the same way, but using strtod instead.
First of all, istringstream is not an operator. It is an input stream class to operate on strings.
You may do something like the following:
istringstream temp(value);
temp>> value;
cout << "value = " << value;
You can find a simple example of istringstream usage here: http://www.cplusplus.com/reference/sstream/istringstream/istringstream/
I've got a data file that is a single line consisting of a nested series of doubles eg.
[[0.127279,0.763675,0.636396],[0.254558,0.890955,0.636396],
[0.127279,0.636396,0.763675],[0.254558,0.763675,0.763675],
[0.381838,0.890955,0.763675],[0.127279,0.509117,0.890955],
[0.254558,0.636396,0.890955],[0.509117,0.890955,0.890955]]
I'd like to be able to read this into a STL vector<vector<double> > using the stream operator which is templated across the inner type of A:
vector<vector<double> > A;
FIN >> A;
I've figured out a way to do this when the vector is not nested, ie. a simple vector<T> as so:
template <class T>
istream& operator>>(istream& s, vector<T> &A){
T x;
string token; char blank;
s >> blank; // Gobble the first '['
while( getline(s, token, ',') ) {
istringstream input(token);
input >> x;
A.push_back(x);
}
s >> blank; // Gobble the last ']'
return s;
}
But I'm having problem with the istream& operator>>(istream& s, vector<vector<T> >&A) part as I can't seem to catch the inner ]'s properly. I'm sure that Boost has a way of doing this, but I'd like to see a solution with the STL for pedagogical purposes.
Note: I'm aware that overloading the stream operator for vector<T> can have far-reaching undesirable consequences and that the implementation should be wrapped up in its own class - I'm using this example above as it stands to clarify the question.
EDIT:
I'd like the method to be robust enough to handle a input array whose size (and inner array) size is not known in advance, but inferred from reading the stream.
Actually, the problem with your code that you want to use the same function for both, when T is:
vector<double>
double
But the logic which needs to read the data into vector and double is slightly different. So you cannot do that, at least not with that simple logic:
I would prefer to write two functions, to handle both cases separately. After all, even in your case, the compiler will generate two different functions for each value of T.
template <class T>
istream& operator>>(istream& s, vector<T> &A)
{
T x;
string token; char blank;
s >> blank; // Gobble the first '['
while( getline(s, token, ',') )
{
istringstream input(token);
input >> x;
A.push_back(x);
}
// s >> blank; // Gobble the last ']'
return s;
}
template <class T>
istream& operator>>(istream& s, vector<vector<T>> &A)
{
vector<T> x;
string token;
char blank;
s >> blank; // Gobble the first '['
while( getline(s, token, ']') )
{
istringstream input(token);
input >> x;
s >> blank; //read , after [...]
A.push_back(x);
x.clear();
}
s >> blank; // Gobble the last ']'
return s;
}
Test code:
int main() {
vector<vector<double>> A;
cin >> A;
for(size_t i = 0 ;i < A.size(); ++i)
{
for(size_t j = 0 ; j < A[i].size(); ++j)
cout << A[i][j] <<" ";
cout << endl;
}
return 0;
}
Input:
[[1,2,3],[4,5,6],
[7,8,9],[10,11,12],
[13,14,15],[16,17,18],
[19,20,21],[22,23,24]]
Output:
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
Online demo : http://ideone.com/iBbmw
In your particular example which is very simple.
Read the whole line into a string.
Replace all [ , ] and , with whitespace character.
Create a simple stringstream with whitespace replaced string.
Now you can have a a simple loop of
double x;
while( stringstreamp >> x )
{
}
And some special logic after reading three doubles to insert them them into a new array.
Some years later, and I was here struggling with the same problem.
Based on your contribution, I developed a modified version of the original template. This one is able to parse multidimensional arrays, even if they are spread across several lines.
template <class T>
istream& operator>>(istream& s, vector<T> &A){
while(true){
T x;
char c = s.peek();
if( c == '[' || c == ','){
s.ignore();
if(s >> x) A.push_back(x);
else throw invalid_argument("Bad, bad JS array!");
continue;
}
if( c == ']') {
s.ignore();
return s;
}
/* Ignore line-break */
s.ignore();
}
return s;
}
Hope this can be useful for someone.
When I use getline, I would input a bunch of strings or numbers, but I only want the while loop to output the "word" if it is not a number.
So is there any way to check if "word" is a number or not? I know I could use atoi() for
C-strings but how about for strings of the string class?
int main () {
stringstream ss (stringstream::in | stringstream::out);
string word;
string str;
getline(cin,str);
ss<<str;
while(ss>>word)
{
//if( )
cout<<word<<endl;
}
}
Another version...
Use strtol, wrapping it inside a simple function to hide its complexity :
inline bool isInteger(const std::string & s)
{
if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p;
strtol(s.c_str(), &p, 10);
return (*p == 0);
}
Why strtol ?
As far as I love C++, sometimes the C API is the best answer as far as I am concerned:
using exceptions is overkill for a test that is authorized to fail
the temporary stream object creation by the lexical cast is overkill and over-inefficient when the C standard library has a little known dedicated function that does the job.
How does it work ?
strtol seems quite raw at first glance, so an explanation will make the code simpler to read :
strtol will parse the string, stopping at the first character that cannot be considered part of an integer. If you provide p (as I did above), it sets p right at this first non-integer character.
My reasoning is that if p is not set to the end of the string (the 0 character), then there is a non-integer character in the string s, meaning s is not a correct integer.
The first tests are there to eliminate corner cases (leading spaces, empty string, etc.).
This function should be, of course, customized to your needs (are leading spaces an error? etc.).
Sources :
See the description of strtol at: http://en.cppreference.com/w/cpp/string/byte/strtol.
See, too, the description of strtol's sister functions (strtod, strtoul, etc.).
The accepted answer will give a false positive if the input is a number plus text, because "stol" will convert the firsts digits and ignore the rest.
I like the following version the most, since it's a nice one-liner that doesn't need to define a function and you can just copy and paste wherever you need it.
#include <string>
...
std::string s;
bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);
EDIT: if you like this implementation but you do want to use it as a function, then this should do:
bool has_only_digits(const string s){
return s.find_first_not_of( "0123456789" ) == string::npos;
}
You might try boost::lexical_cast. It throws an bad_lexical_cast exception if it fails.
In your case:
int number;
try
{
number = boost::lexical_cast<int>(word);
}
catch(boost::bad_lexical_cast& e)
{
std::cout << word << "isn't a number" << std::endl;
}
If you're just checking if word is a number, that's not too hard:
#include <ctype.h>
...
string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
isNumber &&= isdigit(*k);
Optimize as desired.
Use the all-powerful C stdio/string functions:
int dummy_int;
int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);
if (scan_value == 0)
// does not start with integer
else
// starts with integer
You can use boost::lexical_cast, as suggested, but if you have any prior knowledge about the strings (i.e. that if a string contains an integer literal it won't have any leading space, or that integers are never written with exponents), then rolling your own function should be both more efficient, and not particularly difficult.
Ok, the way I see it you have 3 options.
1: If you simply wish to check whether the number is an integer, and don't care about converting it, but simply wish to keep it as a string and don't care about potential overflows, checking whether it matches a regex for an integer would be ideal here.
2: You can use boost::lexical_cast and then catch a potential boost::bad_lexical_cast exception to see if the conversion failed. This would work well if you can use boost and if failing the conversion is an exceptional condition.
3: Roll your own function similar to lexical_cast that checks the conversion and returns true/false depending on whether it's successful or not. This would work in case 1 & 2 doesn't fit your requirements.
Here is another solution.
try
{
(void) std::stoi(myString); //cast to void to ignore the return value
//Success! myString contained an integer
}
catch (const std::logic_error &e)
{
//Failure! myString did not contain an integer
}
Since C++11 you can make use of std::all_of and ::isdigit:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string_view>
int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[])
{
auto isInt = [](std::string_view str) -> bool {
return std::all_of(str.cbegin(), str.cend(), ::isdigit);
};
for(auto &test : {"abc", "123abc", "123.0", "+123", "-123", "123"}) {
std::cout << "Is '" << test << "' numeric? "
<< (isInt(test) ? "true" : "false") << std::endl;
}
return 0;
}
Check out the result with Godbolt.
template <typename T>
const T to(const string& sval)
{
T val;
stringstream ss;
ss << sval;
ss >> val;
if(ss.fail())
throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
return val;
}
And then you can use it like that:
double d = to<double>("4.3");
or
int i = to<int>("4123");
I have modified paercebal's method to meet my needs:
typedef std::string String;
bool isInt(const String& s, int base){
if(s.empty() || std::isspace(s[0])) return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isPositiveInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isNegativeInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
Note:
You can check for various bases (binary, oct, hex and others)
Make sure you don't pass 1, negative value or value >36 as base.
If you pass 0 as the base, it will auto detect the base i.e for a string starting with 0x will be treated as hex and string starting with 0 will be treated as oct. The characters are case-insensitive.
Any white space in string will make it return false.
I have a string of class string
string str;
how can I check if it is a number or not, str can only have 3 possible types described below like
abcd
or a number like
123.4
or a number with a parenthesis attach to the end it for example
456)
note the parenthesis at the end of "str" is the only possible combination of number and none number
where the bottom two are considered valid numbers, I know I could use lexical_cast if only the first 2 cases occur, but how about considering all 3 possible cases to occur?
I don't need to do anything fancy with str, I just need to know whether it is a valid number as I described
The C++ solution for parsing strings manually is string streams. Put your string into a std::istringstream and read from that.
What you could do to parse this is to try to read an (unsigned) int from the string.
If this fails, it is a string not starting with digits.
If it works, peek at the next character. If that's a . you have a floating point number, if it's a ), you have an integer number. (Otherwise you have a reading error.)
Something along the lines of
void read(const std::string& str)
{
std::istringstream iss(str);
int i;
if( !(iss>>i) ) {
// str contains "abcd"
} else {
switch( iss.peek() ) {
case ')':
// i contains '456'
break;
case '.' {
double d;
if( !(iss>>d) ) throw "dammit!";
d += i;
// d contains floating point value
break;
default: throw "what?!";
}
// ...
}
Does this make sense?
You have to define "number". There isn't a generic "number" type (for example, your first number is a double while the second is an integer).
That said, as shown in this answer, lexical_cast simply checks that the destination and only the destination exists:
template <typename R, typename T>
R lexical_cast(const T& pX)
{
std::stringstream ss;
ss << pX;
R result; // take out any whitespace, make sure nothing is left
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
So just make a new function:
template <typename R, typename T>
R weak_lexical_cast(const T& pX)
{
std::stringstream ss;
ss << pX;
R result;
if ((ss >> result).fail())
{
throw std::bad_cast();
}
return result;
}
It's basically a lexical_cast but doesn't care about any remaining characters (allowing your second number to work.)
maybe a regular expression would do the trick for you.