开发者

How can I check if a number (double type) stored as a string is a valid double number in C++?

开发者 https://www.devze.com 2022-12-18 14:15 出处:网络
I\'m having an issue with a program I\'m working on in C++. I am asking the user to input a valid number. I take it in as a string because the particular assignment I\'m doing, it makes it easier in t

I'm having an issue with a program I'm working on in C++. I am asking the user to input a valid number. I take it in as a string because the particular assignment I'm doing, it makes it easier in the long run. For basic error checking, I want to check to see if the number entered is a valid number. Example:

Ent开发者_如何学Cer number: 3.14
This would be valid

Enter number: 3.1456.365.12
This shouldn't be valid


use strtod, which converts a string to a double and returns any characters it couldn't interpret as part of the double.

double strtod(const char* nptr, char** endptr)

Like this:

char* input = "3.1456.365.12";
char* end;

strtod(input, &end);
if (*input == '\0')
{
  printf("fail due to empty string\n");
}
if (end == input || *end != '\0')
{
  printf("fail - the following characters are not part of a double\n%s\n", end);
}


I think boost::lexical_cast should help you here


An example using only standard C++:

#include <sstream>

// ...

double dbl = 0.0;
std::istringstream num("3.1456.365.12");

num >> dbl;

if(!num.fail() &&
   num.eof()) // This second test is important! This makes sure that the entire string was converted to a number
{
    // success
}
else
{
    // failure
}

Bonus generic template function version:

#include <sstream>
#include <string>
#include <exception>

// Version that throws an exception on a bad parse:

template <typename T>
T parse(const std::string& str)
{
    T value;
    std::istringstream parser(str);
    parser >> value;

    if(!parser.fail() && parser.eof())
    {
        return value;
    }
    else
    {
        throw "bad lexical cast";
    }
}

// usage:

double foo = parse<double>("3.14234");

// Non-exception, error code version

template <typename T>
bool parse(const std::string& str, T& value)
{
    std::istringstream parser(str);
    parser >> value;

    return (!parser.fail() && parser.eof());
}

// usage:

double foo = 0.0;
bool success = parser<double>("3.11234", foo);


If you have no boost, you always can use strtod


You can use strtoX (where X is f for float, l for long, ul for unsigned long, etc.), choosing for the kind of number you want. One of the parameters you give it is an "end pointer", which points to the first character in the string that could not be converted into the target number type.

In your case, what you're apparently looking for is that the end pointer should be at the end of the string, indicating that all characters in the string were converted to the target type.

Edit: Sorry, didn't notice that you'd mentioned 'double' in the title (but not the question itself). That being the case, you'd use strtod, as a couple of others have also advised.


The best way is to make an actual attempt to convert your string to double using any of the standard and/or idiomatic ways to do the conversion, and check for errors afterwards. In C that would be functions from strto... group (which are, of course, perfectly usable in C++ as well). In C++ you can use stream-based conversion idiom.

One thing to watch for though is that the common convention in standard conversion methods is to convert "as much as possible" and not consider any extra characters as an error. For example, a string "123abc" is normally considered valid input, with only "123" part getting converted. All usable methods provide you with the way to detect the fact that there is something extra after the actual number, if you want to treat this situation as an error. But it is up to you to take the additional steps to perform this verification.


A simple option is to use the sscanf function:

const char * num_as_str = "3.1416";
double num;

if(std::sscanf(num_as_str, "%lg", &num) == 1)
{ 
    std::cout << "You correctly entered the number " << num << "\n";
} 

If you want to get fancy you can use istringstream:

std::istringstream iss(num_as_str);
if(iss >> num)
{
    std::cout << "You correctly entered the number " << num << "\n";
}

If you want to get extra-fancy you can use boost's lexical_cast:

try
{
    num = boost::lexical_cast<double>(num_as_str);
}
catch(boost::bad_lexical_cast &)
{ 
    std::cout << "What you entered is not a proper number" << num << "\n";
}


Ah, I loved these assignments. A good old hand written lexer is the way to go (since you are still in the begining days -- don't try to use boost just yet). They are fast, easy to write and extremely fun to play with. If you can get a copy of Levine's book on Lex/Yacc, look up the first couple of chapters for ideas.


As mentioned by AndreyT, the best way is to attempt to convert the string into a float and check for an error. Personally I would opt to use std::istringstream, as you're using C++. Something like the following should work:

float ff;
std::istringstream istr;
std::string input("1234.5678");

// set the stream to have your string as its base
istr.str(input);

// now try to read the number:
istr >> ff;
if (istr.fail())
{
    // some error in the parsing
}

istringstream is part of STL, so you shouldn't need any additional libraries, and it will also with with exceptions if that's your choice. More information can be found here: http://www.cplusplus.com/reference/iostream/istringstream/


You could use regular expressions. Since you already have a string, it would be easy to compare that with this regex:

/^\d+(\.\d+)?$/

The library regex.h can help you here. See this: regex.h


This is my quick hack :)

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

template <typename T>
bool fromStr(const std::string& str, T& var)
{
    std::stringstream convertor;
    convertor << str;
    convertor >> var;

    if( convertor.fail() )
        return false;

    char c = static_cast<char>( convertor.get() );

    return convertor.eof() || c == '\n' || c == ' ' || c == '\t';
}

int main()
{
    double d;
    std::string str = "5.04146.55";

    if( fromStr<double>(str, d) )
    {
        std::cout << "Valid conversion!, d = " << d;
    }
    else
    {
        std::cout << "Invalid conversion!";
    }   
}
0

精彩评论

暂无评论...
验证码 换一张
取 消