helmet91
helmet91

Reputation: 127

How to check if a string can be converted to double in C++?

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

Answers (6)

Plecharts
Plecharts

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

mcpp
mcpp

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

nowox
nowox

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

Malcolm McLean
Malcolm McLean

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

Alexey Nikitenko
Alexey Nikitenko

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

P0W
P0W

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

Related Questions