Reputation: 127
I have a string which can be a number (even a float or double type, not only integer), and it can be also a word which is non-numeric.
I would like to check if this string can be converted into double, and if so, then I would like to do the conversion. In case of a non-numeric string, I want different behaviour.
I have tried this:
double tmp;
string str;
stringstream ss;
ss << str;
ss >> tmp;
if (ss.fail())
{
// non-numeric string
}
else
{
// string to double conversion is successful
}
The problem with this code is that ss.fail()
is always true
, even if tmp
contains the right value.
There is a function called atof()
which converts string to double, but this is not suitable for me, becouse it returns 0.0
value if the input string is non-numeric. This way I cannot make difference between a non-numeric and a zero input value.
Upvotes: 7
Views: 13985
Reputation: 311
What about std::stod? It will throw std::out_of_range when it can't perform the conversion.
try
{
double value = std::stod(input_string);
std::cout << "Converted string to a value of " << value << std::endl;
}
catch (const std::invalid_argument&)
{
std::cerr << "No conversion could be performed" << std::endl;
}
catch (const std::out_of_range&)
{
std::cerr << "Could not convert string to double, value falls out of range" << std::endl;
}
I haven't tried to compile it, but you should get the idea.
Upvotes: 8
Reputation: 11
Be careful to use std::ws as it triggers failbit if its already EOF. So the below suggestion wont work for the cases like "9.000". This was working in Visual Studio 2015 because of a cl bug. But in VS2019 the bug is fixed and it fails.
if ((ss >> tmp) && (ss >> std::ws).eof() )
{
// a double
}
You can consider below code instead
if ((ss >> tmp) && ( ss.eof() || (ss >> std::ws).eof()) )
{
// a double
}
Details on VS bug: https://developercommunity.visualstudio.com/t/regression-stdws-incorrectly-sets-failbit-when-the/382896
Upvotes: 1
Reputation: 29066
What about a less cpp-ish solution:
double number;
string str;
if (sscanf(str.c_str(), "%lf", &number) != 1)
{
// non-numeric string
}
else
{
// string to double conversion is successful
}
Upvotes: 0
Reputation: 6406
What is a valid number? Is it anything that atof() will parse, or do you have rules on whitespace? Do you allow scientific notation, leading -, leading + ? May other data follow the number? Must there be a decimal point or do you accept integers? Do you accept a bare leading decimal point or must it be preceded by 0? Do you accept 00.1 ? Do you accept 0.1FRED but reject 0.1.2FRED ?
The function strtod() is designed for this problem. atof() is essentially obsolete now, because it is not robust enough to handle malformed input. However strtod() isn't flexible enough to accept particular rules for well-formed input. If the rules are simple, it's not to hard to write your own ad-hoc matcher- skip whitepspace, match digits, match decimal point, match digits, skip whitespace. If you need total flexiblity, eventually you have to resort to regular expressions, which are a kind of sledgehammer answer.
Upvotes: -1
Reputation: 2127
You can use this function if your input string have type from std::string (it works on windows and unix systems):
#include <stdlib.h>
#include <string>
/**
* @brief checkIsDouble - check inputString is double and if true return double result
* @param inputString - string for checking
* @param result - return double value
* @return true if string is double, false if not
*/
bool checkIsDouble(string inputString, double &result) {
char* end;
result = strtod(inputString.c_str(), &end);
if (end == inputString.c_str() || *end != '\0') return false;
return true;
}
Upvotes: 11
Reputation: 47784
Check for white-space and end of stream too
if ((ss >> tmp) && (ss >> std::ws).eof() )
{
// a double
}
Extract a double
value and then any whitespace, if eof is encountered during this it means you have a valid double
only
Upvotes: 1