152

I've had quite a bit of trouble trying to write a function that checks if a string is a number. For a game I am writing I just need to check if a line from the file I am reading is a number or not (I will know if it is a parameter this way). I wrote the below function which I believe was working smoothly (or I accidentally edited to stop it or I'm schizophrenic or Windows is schizophrenic):

bool isParam (string line)
{
    if (isdigit(atoi(line.c_str())))
        return true;

    return false;
}
Enigma
  • 1,151
  • 3
  • 19
  • 51
Brendan Weinstein
  • 6,382
  • 6
  • 22
  • 29
  • 202
    I **hate** seeing `if (expr) return true; return false;`! Just write `return expr;`. – ephemient Jan 11 '11 at 06:08
  • 22
    @ephemient My style is to do the same as you. But is it really a big deal? – Brennan Vincent Jan 11 '11 at 06:12
  • 2
    Your function prototype seems not appropriate. Why not use bool isParam(const string& line) – MikimotoH Jan 11 '11 at 06:34
  • 4
    Yeah. I have a bad habit of coding long-style when learning a new language. I am new to C++ and more hesitant to "shortcuts" (or perceived shortcuts). – Brendan Weinstein Jan 11 '11 at 06:59
  • 63
    @Brennan Vincent: Yes, it's a big deal. It's the same class of mistakes as `if (expr) return expr; else return expr;` , `if (expr == true)` , `(if expr != false)`, or `if ((expr == true) == true)`. They all introduce complexity that does not benefit the writer, reader, or compiler of the code. The elimination of needless complexity is not a shortcut; it's key to writing better software. – MSalters Jan 11 '11 at 08:24
  • 2
    @MSalters Personally I do not think the OP's version is necessarily that bad.I use this construct when I suspect there might be more code between the if statement and the return statement. Only when I know for sure there is not going to be anything else, I collapse it to return expr. – TStancek Mar 18 '19 at 11:29
  • if you want to know why his code is not working, check Brendan Weinstein and Tony Delroy answer below. – Ben_LCDB Sep 15 '20 at 18:34

32 Answers32

161

The most efficient way would be just to iterate over the string until you find a non-digit character. If there are any non-digit characters, you can consider the string not a number.

bool is_number(const std::string& s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

Or if you want to do it the C++11 way:

bool is_number(const std::string& s)
{
    return !s.empty() && std::find_if(s.begin(), 
        s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
}

As pointed out in the comments below, this only works for positive integers. If you need to detect negative integers or fractions, you should go with a more robust library-based solution. Although, adding support for negative integers is pretty trivial.

user31264
  • 5,774
  • 3
  • 18
  • 35
Charles Salvia
  • 48,775
  • 12
  • 118
  • 138
  • 6
    Also doesn't handle negative numbers and non-whole numbers. We can't know what the requirements are based on the question. – Brennan Vincent Jan 11 '11 at 06:24
  • Yeah. Sorry I should have been more specific. I know the numbers I am looking for are positive. This solution works very well. – Brendan Weinstein Jan 11 '11 at 06:36
  • 78
    You could also use `!s.empty() && s.find_first_not_of("0123456789") == std::string::npos;` for a C++03 one-liner. – kbjorklu Jan 11 '11 at 07:03
  • 10
    Also doesn't handle decimal numbers eg: 1.23 – littlecodefarmer758 Mar 10 '13 at 09:31
  • To handle signed integers, after the `std::string::const_iterator it = s.begin();` line you can add `if(s[0] == '-' || s[0] == '+') it++;`.Just being sure not empty input coming. – Fredrick Gauss Mar 17 '13 at 22:40
  • Doesn't handle decimal numbers and scientific notation numbers!! – Daniel Apr 11 '13 at 20:12
  • 2
    And doesn't handle large numbers that do not fit in `int`. – Remy Lebeau May 15 '13 at 22:42
  • 4
    @Remy Lebeau, yes it does. It's not actually converting the string to an `int`. It's just identifying whether a string is composed of numeric digits. It doesn't matter how long the string is. – Charles Salvia May 16 '13 at 18:21
  • @CharlesSalvia: The point I was trying to make is if a string is longer than 9 digits, it will likely not convert to `int` should the code need to do that conversion after validating the string. So the string length should be validated to make sure that the actual string contents are suitable for whatever purpose the string is going to be used for. Just checking for non-digits is not good enough if the string length is also not suitable. – Remy Lebeau May 16 '13 at 19:08
  • 1
    This solution seems to be ugly and inflexible for me. Using regular expression is the most straightforward solution for a parsing task. This solution is not extensible (try writing matching a floating point number in the same style), does not check the sign, has logical flaws that have been found above, is much more complicated than a regexp. – Dmytro Sirenko Jul 31 '13 at 17:45
  • @FredrickGauss There's a problem with this approach: Even "-" or "+" is considered a number then. There is an additional check required instead of !string.empty() in the end i.e. `static bool isIntegerNumber(const std::string& string){ std::string::const_iterator it = string.begin(); int minSize = 0; if(string.size()>0 && (string[0] == '-' || string[0] == '+')){ it++; minSize++; } while (it != string.end() && std::isdigit(*it)) ++it; return string.size()>minSize && it == string.end(); }` – Constantin Nov 05 '13 at 21:49
  • 1
    Thanks for noticing @Constantin. Edit for my suggestion: To handle signed integers, after the `std::string::const_iterator it = s.begin();` line you can add `if(s.size() > 1 && (s[0] == '-' || s[0] == '+')) it++;` – Fredrick Gauss Nov 10 '13 at 07:52
  • 5
    Don't forget to include `` `` and `` to make the C++11 example work. – kR105 Nov 04 '14 at 18:40
  • 1
    @kR105 you're a hero! I really wish people got into the habit of mentioning which libraries they use in their anwers – Scy Mar 26 '16 at 18:01
  • 1
    A good answer should work for all numbers like `3.2+e15, 3.2-e27, 3.2+E45, 44.9L`, etc. – MVTC Jan 30 '17 at 03:40
96

Why reinvent the wheel? The C standard library (available in C++ as well) has a function that does exactly this:

char* p;
long converted = strtol(s, &p, 10);
if (*p) {
    // conversion failed because the input wasn't a number
}
else {
    // use converted
}

If you want to handle fractions or scientific notation, go with strtod instead (you'll get a double result).

If you want to allow hexadecimal and octal constants in C/C++ style ("0xABC"), then make the last parameter 0 instead.

Your function then can be written as

bool isParam(string line)
{
    char* p;
    strtol(line.c_str(), &p, 10);
    return *p == 0;
}
Ben Voigt
  • 260,885
  • 36
  • 380
  • 671
  • 4
    This function discards white space in front. You thus have to check first char for isdigit. – chmike Jun 24 '13 at 08:51
  • 1
    @chmike: Based on my understanding of the question, discarding leading whitespace is the correct behavior (`atoi` as used in the question does this also). – Ben Voigt Jun 24 '13 at 12:21
  • 1
    The question didn't explicitly specify it, but my understanding of the requirement "checks if a string is a number" means that the whole string is the number, thus no spaces. I felt the need to point out that your answer is different to the others in this regard. Your answer may be fine if it's ok for the string to have spaces in front of the number. – chmike Jul 01 '13 at 10:53
  • 2
    @BenVoigt You're saying that `p` will be set to `nullptr` if `strtol` is sucessful, right? That's not what I'm seeing :( – Jonathan Mee Nov 13 '14 at 21:21
  • 2
    @JonathanMee: No, `p` will be pointing to the NUL that terminates the string. So `p != 0` and `*p == 0`. – Ben Voigt Nov 13 '14 at 21:23
  • The above code doesn't handle decimal places, and `strtod` thinks that "NaN" is a number. – Steve Smith Aug 07 '18 at 13:18
  • @Steve: `strtol` doesn't handle decimal places, because it is designed not to. `long` is an integral type. `strtod` doesn't think "NaN" is a number, it thinks it is a valid `double`.... and it is correct about that. If you want to test that something is a finite double, it is trivial to combine `strtod` with `isfinite`. There doesn't need to be a separate function for every possibility "finite double", "strictly positive double", "non-negative double", etc. – Ben Voigt Aug 08 '18 at 04:00
  • The problem of strtol is, if the string is "0" how can you be sure ? – Jackt Sep 06 '19 at 17:23
  • 1
    @Jackt: As already explained, to see if parsing was successful check if `*p == 0` not the return value. – Ben Voigt Sep 08 '19 at 23:45
  • what if line contains trailing whitespace? – matthias_buehlmann Jan 25 '20 at 13:10
  • @user1282931: Then `*p == 0 || iswhite(*p)`. But that would be a different behavior than the one wanted in the question, which indicated `atoi`. – Ben Voigt Jan 27 '20 at 15:48
  • @user1282931: What did the documentation for `strtol` say when you read it? – Ben Voigt Jan 27 '20 at 17:47
  • @Ben Voigt that's the thing, it doesn't say what happens to p if the conversion fails. As such iswhite(*p) might be true if the conversion failed – matthias_buehlmann Jan 27 '20 at 18:13
  • @user1282931: `p` is left pointing where the conversion stopped (specifically, to the first character which couldn't be converted). Unless the conversion never started at all (because no digits were found), then `p` equals the input pointer. The [official specification](https://pubs.opengroup.org/onlinepubs/7908799/xsh/strtol.html) has a roundabout description of this involving a "final string", but the [Linux man page](http://man7.org/linux/man-pages/man3/strtol.3.html) gives a pretty straightforward description of the same rule. – Ben Voigt Jan 27 '20 at 19:09
  • [cppreference also describes how `p` is determined pretty clearly](https://en.cppreference.com/w/c/string/byte/strtol): "The functions sets the pointer pointed to by str_end to point to the character past the last character interpreted. If str_end is NULL, it is ignored. If the str is empty or does not have the expected form, no conversion is performed, and (if str_end is not NULL) the value of str is stored in the object pointed to by str_end." – Ben Voigt Jan 27 '20 at 19:13
45

With C++11 compiler, for non-negative integers I would use something like this (note the :: instead of std::):

bool is_number(const std::string &s) {
  return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}

http://ideone.com/OjVJWh

iNFINITEi
  • 1,374
  • 14
  • 22
szx
  • 5,012
  • 5
  • 36
  • 59
29

You can do it the C++ way with boost::lexical_cast. If you really insist on not using boost you can just examine what it does and do that. It's pretty simple.

try 
{
  double x = boost::lexical_cast<double>(str); // double could be anything with >> operator.
}
catch(...) { oops, not a number }
Edward Strange
  • 38,861
  • 7
  • 65
  • 123
  • 21
    Using `try{} catch{}` a good idea? Should we not avoid it as much as possible? – Nawaz Jan 11 '11 at 06:17
  • 2
    @Nawaz: No. There's a reason it's part of the C++ language. Like all C++ constructs, it should be used in the appropriate places. Given that the file read operation is I/O bound anyway, this doesn't seem excessive. – MSalters Jan 11 '11 at 08:27
  • 3
    Nawaz - there's no way to avoid it here. If you'd like to avoid it then you need to rewrite lexical_cast. As it is, lexical_cast is behaving correctly. If the value in the string is not a number then it can't do its job. This IS an exceptional situation for that function. – Edward Strange Jan 11 '11 at 17:19
  • 33
    -1 for abusing try catch... https://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx?Redirected=true – NoSenseEtAl Nov 28 '12 at 09:59
  • 15
    try{} catch{} is appropriate here. However, catch(...) is just bad practice. In this case, use boost::bad_lexical_cast for your exception handler. – NuSkooler Feb 07 '13 at 17:59
  • 5
    I feel like this is trying to read from a file. NO matter how much checking you do on the file you will not know if it's possible to read from it until you do it. It's either going to work or not. In which case you are going to need to catch an exception. So in this case I think this is a completely fine way of doing it. – Casey May 10 '13 at 00:06
  • 2
    It's an abuse of exceptions, on Windows this would cause OS-dependent actions, which is not acceptable for a simple number decoding task. – Dmytro Sirenko Jul 31 '13 at 17:48
  • 5
    @EarlGray - I would certainly be interested in hearing what OS dependent actions windows would take. The standard is quite clear about how this code should behave. – Edward Strange Aug 02 '13 at 00:46
  • @NoSenseEtAl Your own link says that try catch SHOULD be used in this case. "Vexing exceptions are thrown in a completely non-exceptional circumstance, and therefore must be caught and handled all the time." – vll Mar 09 '17 at 06:36
  • @Ville-ValtteriTiittanen: That's the definition of a vexing exception, not guidance to use them. (Note the quote said "must", you paraphrased incorrectly as "should") – Ben Voigt May 16 '17 at 14:16
  • @BenVoigt How do you understand this part about converting strings to numbers? "The classic example of a vexing exception is Int32.Parse, which throws if you give it a string that cannot be parsed as an integer. But the 99% use case for this method is transforming strings input by the user, which could be any old thing, and therefore it is in no way exceptional for the parse to fail. -- You have to catch vexing exceptions" – vll May 17 '17 at 06:20
  • @Ville-ValtteriTiittanen: Keep reading, pay attention to where it says "Try to never write a library yourself that throws a vexing exception." and " Avoid vexing exceptions whenever possible by calling the “Try” versions of those vexing methods that throw in non-exceptional circumstances. If you cannot avoid calling a vexing method, catch its vexing exceptions." Well, you can avoid calling the function that produces a vexing exception. `boost::lexical_cast` is the version with vexing exceptions (bad!), `strtod` is the version which reports expected failures without using exceptions (good!) – Ben Voigt May 17 '17 at 07:41
  • 1
    Buried down in the answer list is `boost::conversion::try_lexical_convert<>` as shown in @NoSenseEtAl answer: https://stackoverflow.com/a/42796837/1797414 This seems to me to be more sensible way to use `lexical_cast` for those enticed by this answer but troubled by abuse of `try/catch` – arr_sea Sep 12 '20 at 01:05
17

I just wanted to throw in this idea that uses iteration but some other code does that iteration:

#include <string.h>

bool is_number(const std::string& s)
{
    return( strspn( s.c_str(), "-.0123456789" ) == s.size() );
}

It's not robust like it should be when checking for a decimal point or minus sign since it allows there to be more than one of each and in any location. The good thing is that it's a single line of code and doesn't require a third-party library.

Take out the '.' and '-' if positive integers are all that are allowed.

David Rector
  • 809
  • 9
  • 25
  • error: 'strspn' was not declared in this scope I think this is because I am missing a "#include" but what one – Qwertie Jan 22 '14 at 01:42
  • 4
    If you're going to use `std::string`, use its `find_first_not_of` member function. – Ben Voigt Apr 02 '14 at 16:36
  • 6
    This would fail if you pass in a string of "12.3-4.55-", which is obviously not a valid number – Buzzrick Aug 15 '14 at 00:22
  • Buzzrick, the proposed answer already states that this would fail with the non-number you mentioned. – David Rector Nov 09 '17 at 00:34
  • if you limit it only to "0123456789" then the formula is perfect to test for unsigned integer – no one special Feb 13 '19 at 10:44
  • This is not a valid answer. Your code fails for an input like: '1Z' – Sampath Mar 22 '21 at 09:58
  • @Sampath, please explain how this is wrong. This code will return false if "1Z" is passed in. Is "1Z" a number? – David Rector Mar 23 '21 at 18:11
  • @DavidRector: Apologies, I have made a mistake in the example. It should be corrected as: '1-'. Even strings like 1.1.1.1 or 1-2-3-321 would return true. The problem is that the strspn does not check the order nor restrict occurrence count, but simply count occurrences. – Sampath Mar 31 '21 at 17:26
  • @Sampath, if you read my complete answer, that problem of decimal points and minus signs is already mentioned in what I wrote. Your comment does not provide any additional information that I didn't already supply. In fact, all I did was show how strspn() could be used instead of other iteration solutions that others already presented before me. – David Rector Apr 01 '21 at 02:12
  • @DavidRector: I'm afraid you are correct. And your example of `strspn` is good. – Sampath Apr 08 '21 at 04:32
17

I'd suggest a regex approach. A full regex-match (for example, using boost::regex) with

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

would show whether the string is a number or not. This includes positive and negative numbers, integer as well as decimal.

Other variations:

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

(only positive)

-?[0-9]+

(only integer)

[0-9]+

(only positive integer)

StaceyGirl
  • 6,826
  • 12
  • 33
  • 59
Mephane
  • 1,664
  • 10
  • 15
  • Ahem, I tried to use `std::regex` with gcc 4.7, gcc 4.8 - they both throw `std::regex_error` on any sign of `[` in regexp, even for an innocent "[abc]" (do I do that wrong?). clang-3.4 is not aware of `` at all. Anyway, this seems to be the sanest answer, +1. – Dmytro Sirenko Jul 31 '13 at 17:41
  • 3
    @EarlGray: Regex is only available properly from GCC 4.9 – Lightness Races in Orbit Feb 01 '14 at 21:28
13

Here's another way of doing it using the <regex> library:

bool is_integer(const std::string & s){
    return std::regex_match(s, std::regex("[(-|+)|][0-9]+"));
}
mpataki14
  • 178
  • 1
  • 8
  • Ah, so it would. I've updated with a better solution. Thanks. – mpataki14 Mar 20 '14 at 04:00
  • Shouldn't it be "[(-|+)|][0-9]+" (plus instead of star), otherwise your regex could match on "-" or "+" as a valid number. – David Mulder Aug 13 '14 at 18:42
  • Nice. I'm not sure what the (, | and ) are doing in that first character class--those metacharacters lose their special meaning inside a character class as far as I am aware. How about "^[-+]?[0-9]+$"? – U007D Aug 29 '15 at 23:12
  • It may be inefficient. Each time this is called, it calls std::regex constructor which compiles the regex. – user31264 Dec 26 '19 at 08:52
12

With this solution you can check everything from negative to positive numbers and even float numbers. When you change the type of num to integer you will get an error if the string contains a point.

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


int main()
{
      string s;

      cin >> s;

      stringstream ss;
      ss << s;

      float num = 0;

      ss >> num;

      if(ss.good()) {
          cerr << "No Valid Number" << endl;
      }
      else if(num == 0 && s[0] != '0') {
          cerr << "No Valid Number" << endl;
      }
      else {
          cout << num<< endl;
      }             
}

Prove: C++ Program

Kevin Panko
  • 7,844
  • 19
  • 46
  • 58
tzwickl
  • 1,183
  • 1
  • 12
  • 28
11

I've found the following code to be the most robust (c++11). It catches both integers and floats.

#include <regex>
bool isNumber( std::string token )
{
    return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) );
}
dk123
  • 15,184
  • 16
  • 63
  • 74
6

Try this:

isNumber(const std::string &str) {    
  return !str.empty() && str.find_first_not_of("0123456789") == string::npos;
}
GMchris
  • 4,499
  • 4
  • 20
  • 37
Tomasz
  • 111
  • 1
  • 4
5

Here is a solution for checking positive integers:

bool isPositiveInteger(const std::string& s)
{
    return !s.empty() && 
           (std::count_if(s.begin(), s.end(), std::isdigit) == s.size());
}
EvilTeach
  • 26,577
  • 21
  • 79
  • 136
Jaime Soto
  • 3,058
  • 1
  • 19
  • 18
4

Brendan this

bool isNumber(string line) 
{
    return (atoi(line.c_str())); 
}

is almost ok.

assuming any string starting with 0 is a number, Just add a check for this case

bool isNumber(const string &line) 
{
 if (line[0] == '0') return true;
 return (atoi(line.c_str()));
}

ofc "123hello" will return true like Tony D noted.

Noam Geffen
  • 319
  • 2
  • 6
4

As it was revealed to me in an answer to my related question, I feel you should use boost::conversion::try_lexical_convert

Community
  • 1
  • 1
NoSenseEtAl
  • 23,776
  • 22
  • 102
  • 222
3

A solution based on a comment by kbjorklu is:

bool isNumber(const std::string& s)
{
   return !s.empty() && s.find_first_not_of("-.0123456789") == std::string::npos;
}

As with David Rector's answer it is not robust to strings with multiple dots or minus signs, but you can remove those characters to just check for integers.


However, I am partial to a solution, based on Ben Voigt's solution, using strtod in cstdlib to look decimal values, scientific/engineering notation, hexidecimal notation (C++11), or even INF/INFINITY/NAN (C++11) is:

bool isNumberC(const std::string& s)
{
    char* p;
    strtod(s.c_str(), &p);
    return *p == 0;
}
Community
  • 1
  • 1
chappjc
  • 29,576
  • 6
  • 70
  • 120
3

The simplest I can think of in c++

bool isNumber(string s) {
    if(s.size()==0) return false;
    for(int i=0;i<s.size();i++) {
        if((s[i]>='0' && s[i]<='9')==false) {
            return false;
        }
    }
    return true;
}

Working code sample: https://ideone.com/nRX51Y

Abhijit Annaldas
  • 609
  • 4
  • 12
3

My solution using C++11 regex (#include <regex>), it can be used for more precise check, like unsigned int, double etc:

static const std::regex INT_TYPE("[+-]?[0-9]+");
static const std::regex UNSIGNED_INT_TYPE("[+]?[0-9]+");
static const std::regex DOUBLE_TYPE("[+-]?[0-9]+[.]?[0-9]+");
static const std::regex UNSIGNED_DOUBLE_TYPE("[+]?[0-9]+[.]?[0-9]+");

bool isIntegerType(const std::string& str_)
{
  return std::regex_match(str_, INT_TYPE);
}

bool isUnsignedIntegerType(const std::string& str_)
{
  return std::regex_match(str_, UNSIGNED_INT_TYPE);
}

bool isDoubleType(const std::string& str_)
{
  return std::regex_match(str_, DOUBLE_TYPE);
}

bool isUnsignedDoubleType(const std::string& str_)
{
  return std::regex_match(str_, UNSIGNED_DOUBLE_TYPE);
}

You can find this code at http://ideone.com/lyDtfi, this can be easily modified to meet the requirements.

aniliitb10
  • 970
  • 8
  • 14
3

We may use a stringstream class.

    bool isNumeric(string str)
    {
       stringstream stream;                   
       double number;

       stream<<str;
       stream>>number;

       return stream.eof();
    }
rashedcs
  • 2,709
  • 2
  • 29
  • 32
3

Using <regex>. This code was tested!

bool isNumber(const std::string &token)
{
    return std::regex_match(token, std::regex("(\\+|-)?[0-9]*(\\.?([0-9]+))$"));
}
Nery Jr
  • 3,421
  • 23
  • 22
2

Try this:

bool checkDigit(string str)
{  
   int n=str.length();

   for(int i=0;    i   < n ;   i++)
   {
     if(str[i]<'0' || str[i]>'9')
       return false;
   }

   return true;
}
bruno
  • 31,755
  • 7
  • 21
  • 36
rrlinus
  • 21
  • 2
1

I think this regular expression should handle almost all cases

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

so you can try the following function that can work with both (Unicode and ANSI)

bool IsNumber(CString Cs){
Cs.Trim();

#ifdef _UNICODE
std::wstring sr = (LPCWSTR)Cs.GetBuffer(Cs.GetLength());
return std::regex_match(sr, std::wregex(_T("^(\\-|\\+)?[0-9]*(\\.[0-9]+)?")));

#else
    std::string s = (LPCSTR)Cs.GetBuffer();
return std::regex_match(s, std::regex("^(\\-|\\+)?[0-9]*(\\.[0-9]+)?"));
#endif
}
Motaz
  • 170
  • 1
  • 1
  • 14
1

to check if a string is a number integer or floating point or so you could use :

 #include <sstream>

    bool isNumber(string str) {
    double d;
    istringstream is(str);
    is >> d;
    return !is.fail() && is.eof();
}
1
include <string>

For Validating Doubles:

bool validateDouble(const std::string & input) {
int decimals = std::count(input.begin(), input.end(), '.'); // The number of decimals in the string
int negativeSigns = std::count(input.begin(), input.end(), '-'); // The number of negative signs in the string

if (input.size() == decimals + negativeSigns) // Consists of only decimals and negatives or is empty
    return false;
else if (1 < decimals || 1 < negativeSigns) // More than 1 decimal or negative sign
    return false;
else if (1 == negativeSigns && input[0] != '-') // The negative sign (if there is one) is not the first character
    return false;
else if (strspn(input.c_str(), "-.0123456789") != input.size()) // The string contains a character that isn't in "-.0123456789"
    return false;
return true;

}

For Validating Ints (With Negatives)

bool validateInt(const std::string & input) {
int negativeSigns = std::count(input.begin(), input.end(), '-'); // The number of negative signs in the string

if (input.size() == negativeSigns) // Consists of only negatives or is empty
    return false;
else if (1 < negativeSigns) // More than 1 negative sign
    return false;
else if (1 == negativeSigns && input[0] != '-') // The negative sign (if there is one) is not the first character
    return false;
else if (strspn(input.c_str(), "-0123456789") != input.size()) // The string contains a character that isn't in "-0123456789"
    return false;
return true;

}

For Validating Unsigned Ints

bool validateUnsignedInt(const std::string & input) {
return (input.size() != 0 && strspn(input.c_str(), "0123456789") == input.size()); // The string is not empty and contains characters only in "0123456789"

}

1
bool isNumeric(string s){
    if ( !s.empty() && s[0] != '-' )
        s = "0" + s; //prepend 0

    string garbage;

    stringstream ss(s); 
    ss >> *(auto_ptr<double>(new double)) >> garbage;
/*
//the line above extracts the number into an anonymous variable. it could also be done like this:
double x;
ss >> x >> garbage;
*/
    //if there is no garbage return true or else return false
    return garbage.empty(); 
}

how it works: the stringstream >> overload can convert strings to various arithmetic types it does this by reading characters sequentially from the stringstream (ss in this case) until it runs out of characters OR the next character does not meet the criteria to be stored into the destination variable type.

example1:

stringstream ss("11");
double my_number;
ss >> my_number; //my number = 11

example2:

stringstream ss("011");
double my_number;
ss >> my_number; //my number = 11

example3:

stringstream ss("11ABCD");
double my_number;
ss >> my_number; //my number = 11 (even though there are letters after the 11)

the "garbage" variable explanation":

why not just check if extraction into my double has a valid value and then return true if it does?

notice example3 above will still successfully read the number 11 into the my_number variable even if the input string is "11ABCD" (which is not a number).

to handle this case we can do another extraction into a string variable(which I named garbage) which can read anything that may have been left over in the string buffer after the initial extraction into the variable of type double. If anything is left over it will be read into "garbage" which means the full string passed in was not a number (it just begins with one). in this which case we'd want to return false;

the prepended "0" explanation":

attempting to extract a single character into a double will fail(returning 0 into our double) but will still move the string buffer position to after the character. In this case our garbage read will be empty which would cause the function to incorrectly return true. to get around this I prepended a 0 to the string so that if for example the string passed in was "a" it gets changed to "0a" so that the 0 will be extracted into the double and "a" gets extracted into garbage.

prepending a 0 will not affect the value of the number so the number will still be correctly extracted into our double variable.

KorreyD
  • 1,226
  • 8
  • 15
  • 1
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Ajean Nov 23 '15 at 21:15
1

Yet another answer, that uses stold (though you could also use stof/stod if you don't require the precision).

bool isNumeric(const std::string& string)
{
    std::size_t pos;
    long double value = 0.0;

    try
    {
        value = std::stold(string, &pos);
    }
    catch(std::invalid_argument&)
    {
        return false;
    }
    catch(std::out_of_range&)
    {
        return false;
    }

    return pos == string.size() && !std::isnan(value);
}
Tim Angus
  • 613
  • 6
  • 18
1

After consulting the documentation a bit more, I came up with an answer that supports my needs, but probably won't be as helpful for others. Here it is (without the annoying return true and return false statements :-) )

bool isNumber(string line) 
{
    return (atoi(line.c_str())); 
}
Hanlet Escaño
  • 16,246
  • 8
  • 49
  • 70
Brendan Weinstein
  • 6,382
  • 6
  • 22
  • 29
  • 5
    If the number happens to be `0`, you'll get a false-negative. – Charles Salvia Jan 11 '11 at 06:37
  • 3
    This will return any leading number, and not warn you of trailing garbage (e.g. "123hello" ==> 123). @Charles: Brendan mentions he only needs to recognise positive ints in a comment on another answer. – Tony Delroy Jan 11 '11 at 06:58
1

C/C++ style for unsigned integers, using range based for C++11:

int isdigits(const std::string & s)
{
    for (char c : s) if (!isdigit(c)) return (0);
    return (1);
}
Kubator
  • 1,243
  • 2
  • 13
0

Few months ago, I implemented a way to determine if any string is integer, hexadecimal or double.

enum{
        STRING_IS_INVALID_NUMBER=0,
        STRING_IS_HEXA,
        STRING_IS_INT,
        STRING_IS_DOUBLE
};

bool isDigit(char c){
    return (('0' <= c) && (c<='9'));
}

bool isHexaDigit(char c){
    return ((('0' <= c) && (c<='9')) || ((tolower(c)<='a')&&(tolower(c)<='f')));
}


char *ADVANCE_DIGITS(char *aux_p){

    while(CString::isDigit(*aux_p)) aux_p++;
    return aux_p;
}

char *ADVANCE_HEXADIGITS(char *aux_p){

    while(CString::isHexaDigit(*aux_p)) aux_p++;
    return aux_p;
}


int isNumber(const string & test_str_number){
    bool isHexa=false;
    char *str = (char *)test_str_number.c_str();

    switch(*str){
    case '-': str++; // is negative number ...
               break;
    case '0': 
              if(tolower(*str+1)=='x')  {
                  isHexa = true;
                  str+=2;
              }
              break;
    default:
            break;
    };

    char *start_str = str; // saves start position...
    if(isHexa) { // candidate to hexa ...
        str = ADVANCE_HEXADIGITS(str);
        if(str == start_str)
            return STRING_IS_INVALID_NUMBER;

        if(*str == ' ' || *str == 0) 
            return STRING_IS_HEXA;

    }else{ // test if integer or float
        str = ADVANCE_DIGITS(str);
        if(*str=='.') { // is candidate to double
            str++;
            str = ADVANCE_DIGITS(str);
            if(*str == ' ' || *str == 0)
                return STRING_IS_DOUBLE;

            return STRING_IS_INVALID_NUMBER;
        }

        if(*str == ' ' || *str == 0)
            return STRING_IS_INT;

    }

    return STRING_IS_INVALID_NUMBER;


}

Then in your program you can easily convert the number in function its type if you do the following,

string val; // the string to check if number...

switch(isNumber(val)){
   case STRING_IS_HEXA: 
   // use strtol(val.c_str(), NULL, 16); to convert it into conventional hexadecimal
   break;
   case STRING_IS_INT: 
   // use (int)strtol(val.c_str(), NULL, 10); to convert it into conventional integer
   break;
   case STRING_IS_DOUBLE:
   // use atof(val.c_str()); to convert it into conventional float/double
   break;
}

You can realise that the function will return a 0 if the number wasn't detected. The 0 it can be treated as false (like boolean).

Jordi Espada
  • 379
  • 3
  • 10
0

I propose a simple convention:

If conversion to ASCII is > 0 or it starts with 0 then it is a number. It is not perfect but fast.

Something like this:

string token0;

if (atoi(token0.c_str())>0 || isdigit(token0.c_str()[0]) ) { //this is a value
    // do what you need to do...
}
Mardoz
  • 1,597
  • 1
  • 12
  • 24
0

This function takes care of all the possible cases:

bool AppUtilities::checkStringIsNumber(std::string s){
    //Eliminate obvious irritants that could spoil the party
    //Handle special cases here, e.g. return true for "+", "-", "" if they are acceptable as numbers to you
    if (s == "" || s == "." || s == "+" || s == "-" || s == "+." || s == "-.") return false;

    //Remove leading / trailing spaces **IF** they are acceptable to you
    while (s.size() > 0 && s[0] == ' ') s = s.substr(1, s.size() - 1);
    while (s.size() > 0 && s[s.size() - 1] == ' ') s = s.substr(0, s.size() - 1);


    //Remove any leading + or - sign
    if (s[0] == '+' || s[0] == '-')
        s = s.substr(1, s.size() - 1);

    //Remove decimal points
    long prevLength = s.size();

    size_t start_pos = 0;
    while((start_pos = s.find(".", start_pos)) != std::string::npos) 
        s.replace(start_pos, 1, "");

    //If the string had more than 2 decimal points, return false.
    if (prevLength > s.size() + 1) return false;

    //Check that you are left with numbers only!!
    //Courtesy selected answer by Charles Salvia above
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();

    //Tada....
}
Vaibhav Gupta
  • 59
  • 1
  • 5
0

Could you simply use sscanf's return code to determine if it's an int?

bool is_number(const std::string& s)
{
    int value;
    int result = sscanf(valueStr.c_str(), "%d", &value);
    return (result != EOF && readResult != 0);
}
David D
  • 11
  • 2
0

You may test if a string is convertible to integer by using boost::lexical_cast. If it throws bad_lexical_cast exception then string could not be converted, otherwise it can.

See example of such a test program below:

#include <boost/lexical_cast.hpp>
#include <iostream>

int main(int, char** argv)
{
        try
        {
                int x = boost::lexical_cast<int>(argv[1]);
                std::cout << x << " YES\n";
        }
        catch (boost::bad_lexical_cast const &)
        {
                std:: cout << "NO\n";
        }
        return 0;
}

Sample execution:

# ./a.out 12
12 YES
# ./a.out 12/3
NO
Łukasz Ślusarczyk
  • 1,413
  • 9
  • 16
0
bool is_number(const string& s, bool is_signed)
{
    if (s.empty()) return false;

    if (is_signed && (s.front() == '+' || s.front() == '-'))
    {
        return is_number(s.substr(1, s.length() - 1), false);
    }

    auto non_digit = std::find_if(s.begin(), s.end(), [](const char& c) { return !std::isdigit(c); });
    return non_digit == s.end();
}
  • cool, thank you for your answer. to make it even better, please add some text describing how it works. – Kirby Dec 22 '20 at 08:00