12

I'm very new to C++, boost etc.

I would like to know if there is already a function in boost or STL I can use to determine if a string is numeric.

Numeric strings may look like: 100

or

100.52

I know there are tons of examples how to write such a function but I would like to know if there is already a function I can use for this.

I'm looking for a pure C++-solution, not C.

[UPDATE: I'm already using lexical_cast to convert my strings, I'm just wondering if there is a method like is_numeric I can use for this...]

Inno
  • 2,567
  • 5
  • 32
  • 44

9 Answers9

12

No, there's not a ready-made way to do this directly.

You could use boost::lexical_cast<double>(your_string) or std::stod(your_string) and if it throws an exception then your string is not a double.

C++11:

    bool is_a_number = false;
    try
    {
        std::stod(your_string);
        is_a_number = true;
    }
    catch(const std::exception &)
    {
        // if it throws, it's not a number.
    }

Boost:

    bool is_a_number = false;
    try
    {
        lexical_cast<double>(your_string);
        is_a_number = true;
    }
    catch(bad_lexical_cast &)
    {
        // if it throws, it's not a number.
    }
Matt Curtis
  • 23,168
  • 8
  • 60
  • 63
  • 5
    This is a quick solution. There is considerable overhead in doing this (copies + stringstreams + exceptions), and this kind of stuff is often used in loops. Moreover, exception fascists will tell you that you're using an exception for flow control and not for exceptional cases. – Alexandre C. Apr 07 '11 at 08:41
  • @Alexandre Sure, and very worth pointing out, but the OP didn't list any efficiency constraints. – Matt Curtis Apr 07 '11 at 08:52
  • Hi Alexandre, Hi Matt, I justed wanted to know if I have to invent the wheel :). But nonetheless your advice is very welcome, Alexandre! – Inno Apr 08 '11 at 08:08
  • 1
    @Inno Sure! It does seem like the kitchen sink is hidden inside the standard library and boost, but when you take a look under the sink some of the pipes aren't connected :-) – Matt Curtis Apr 08 '11 at 11:02
  • 1
    This is correct but probably outdated/overkill since C++11. See [my answer](https://stackoverflow.com/a/60075448/1753435) for modern C++. – andreee Feb 05 '20 at 12:07
9

boost::regex (or std::regex, if you have C++0x) can be used; you can defined what you want to accept (e.g. in your context, is "0x12E" a number or not?). For C++ integers:

"\\s*[+-]?([1-9][0-9]*|0[0-7]*|0[xX][0-9a-fA-F]+)"

For C++ floating point:

"\\s*[+-]?([0-9]+\\.[0-9]*([Ee][+-]?[0-9]+)?|\\.[0-9]+([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)"

But depending on what you're doing, you might not need to support things that complex. The two examples you cite would be covered by

"[0-9]+(\\.[0-9]*)?"

for example.

If you're going to need the numeric value later, it may also be just as easy to convert the string into an istringstream, and do the convertion immediately. If there's no error, and you extract all of the characters, the string was a number; if not, it wasn't. This will give you less control over the exact format you want to accept, however.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
6

If performance is a concern at all, I would use boost.spirit.qi rather than std::stringstream:

#include <string>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi_numeric.hpp>

bool is_numeric(std::string const& str)
{
    std::string::const_iterator first(str.begin()), last(str.end());
    return boost::spirit::qi::parse(first, last, boost::spirit::double_)
        && first == last;
}

If you want to allow trailing whitespace then do the following instead:

#include <string>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/spirit/include/qi_operator.hpp>

bool is_numeric(std::string const& str)
{
    std::string::const_iterator first(str.begin()), last(str.end());
    return boost::spirit::qi::parse(first, last,
            boost::spirit::double_ >> *boost::spirit::qi::space)
        && first == last;
}
ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • Thanks for drawing my attention to this. I'll keep it in mind for cases where boost::lexical_cast (and thus std::stringstream) might be a little to heavyweight. – arr_sea Feb 03 '18 at 01:39
  • 1
    @arr_sea : Bear in mind that the modern recommendation would be for Spirit.X3 rather than Spirit.Qi unless you're stuck with C++03. :-] – ildjarn Feb 03 '18 at 18:01
3

The following code

The following sentense, return true if "str" is composed of 0~9 only, otherwise, return false.

return str.find_first_not_of("0123456789") == std::string::npos
andreee
  • 4,459
  • 22
  • 42
Jian Hu
  • 31
  • 2
3

Use a stringstream and return true if the convertion "ate" all the characters in the original string (=eof()).

bool is_numeric(const std::string& str) {
    std::stringstream conv;
    double tmp;
    conv << str;
    conv >> tmp;
    return conv.eof();
}
Giovanni Funchal
  • 8,934
  • 13
  • 61
  • 110
  • Is checking eof() really the Right Thing to do ? – Stefan Näwe Apr 07 '11 at 08:23
  • 1
    @Stefan: yes. @Helltone: This can be done in one or two lines: `( std::istringstream( str ) >> num ).ws().eof()`. Note the call to `ws` to strip off trailing spaces, this is optional. (However, this shortcut misses empty or all-whitespace strings. Likewise, your more complete implementation should return `conv && conv.eof()`.) – Potatoswatter Apr 07 '11 at 08:40
  • @Stefan In this case, it's probably appropriate; I'd use `return conv.get() == EOF;` but the difference is probably one of style more than anything else. – James Kanze Apr 07 '11 at 08:54
  • This is actually what lexical_cast does. – Alexandre C. Apr 07 '11 at 09:04
  • @James Kanze OK. That way you don't get a false positive for '2.5a'. – Stefan Näwe Apr 07 '11 at 09:59
  • 2
    @Alexandr C. Except that `lexical_cast` reports the error via an exception; if I understand the question, this is not an exceptional case. Adding the necessary try/catch code ends up requiring as many lines as doing the job yourself. (On the other hand, `lexical_cast` does the job correctly; if you don't know `iostream` that well---and judging from other questions and answers, a lot of people don't---then that may be an important point to consider.) – James Kanze Apr 07 '11 at 11:11
3
bool is_numeric(std::string number)
{
    char* end = 0;
    std::strtod(number.c_str(), &end);

    return end != 0 && *end == 0;
}


bool is_integer(std::string number)
{
    return is_numeric(number.c_str()) && std::strchr(number.c_str(), '.') == 0;
}

Source

Janak Nirmal
  • 22,706
  • 18
  • 63
  • 99
Sergey
  • 244
  • 1
  • 7
2

You could try a lexical_cast on the string.

Stefan Näwe
  • 3,040
  • 1
  • 18
  • 19
1

From C++11, you can simply use one of std::stof, std::stod, std::stold for converting to float, double and long double, respectively. They convert a string to the numerical value or throw an exception, if there's a problem (see the reference). Here is an example with std::stod:

bool isNumeric(const std::string& str) {
  try {
    std::stod(str); // can safely ignore the return value, function is not [[nodiscard]]
    return true;
  }
  catch (const std::exception&) {
    return false;
  }
}

Also have a look at the functions to convert a string to signed and unsigned integers.

andreee
  • 4,459
  • 22
  • 42
0

There is no boost needed, only stl ... A single char could be checked as an int (c >= '0' && c <= '9'), find_if_not will find the first char not matching the condition between [first] and [last]. If no match was found, it will return [last].

If additional chars like space,.- should be checked, add them.

#include <string>
#include <algorithm>
bool isNumeric(std::string strValue) 
{
    if (strValue.empty())
        return false;
    else
        return (std::find_if_not( std::begin(strValue)
                            , std::end(strValue)
                            , [](char c)
                              { return (c >= '0' && c <= '9'); }
                            ) == std::end(strValue)
                );
}

P.S. @Jian Hu is an empty string numeric ?