How to determine if a string is a number with C++?

2018-12-31 18:04发布

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;
}

28条回答
无与为乐者.
2楼-- · 2018-12-31 18:32

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;
}
查看更多
倾城一夜雪
3楼-- · 2018-12-31 18:33

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.

查看更多
无与为乐者.
4楼-- · 2018-12-31 18:35

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

bool isNumber( std::string token )
{
    using namespace std;
    return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) );
}
查看更多
忆尘夕之涩
5楼-- · 2018-12-31 18:35

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).

查看更多
余生无你
6楼-- · 2018-12-31 18:36

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

查看更多
看风景的人
7楼-- · 2018-12-31 18:36
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.

查看更多
登录 后发表回答