如何确定一个string是一个数字与C + +?

我试图写一个函数来检查一个string是否是一个数字,我遇到了很多麻烦。 对于我正在写的游戏,我只需要检查从我正在阅读的文件中的一行是否是一个数字(我会知道这是否是一个参数)。 我写了下面的function,我相信工作顺利(或者我不小心编辑停止它,或者我是精神分裂症或Windows是精神分裂症):

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

最有效的方法是迭代string,直到find非数字字符。 如果有任何非数字字符,可以认为该string不是数字。

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

或者如果你想要这样做的C + + 11的方式:

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

正如下面的评论所指出的,这只适用于正整数。 如果您需要检测负整数或分数,则应该使用更强大的基于库的解决scheme。 虽然增加对负整数的支持是相当微不足道的。

为什么重新发明轮子? C标准库(也可以在C ++中使用)有一个function,可以完全做到这一点:

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

如果你想处理分数或科学记数法,而不是使用strtod (你会得到一个double结果)。

如果要以C / C ++样式( "0xABC" )允许hex和八进制常数,则请改为使用最后一个参数0

你的function可以写成

 bool isParam(string line) { char* p; strtol(line.c_str(), &p, 10); return *p == 0; } 

你可以用boost :: lexical_cast来做C ++的方法。 如果你真的坚持不使用提升,你可以只是研究它做了什么,并做到这一点。 这很简单。

 try { double x = boost::lexical_cast<double>(str); // double could be anything with >> operator. } catch(...) { oops, not a number } 

有了这个解决scheme,你可以检查从负数到正数,甚至浮点数。 当您将num的types更改为整数时,如果string包含一个点,将会出现错误。

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

certificate: C ++程序

我只是想抛出这个使用迭代的想法,但是其他一些代码会这样做:

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

它不像检查小数点或减号时那样健壮,因为它允许每个位置有多于一个的位置。 好的是它是一行代码,不需要第三方库。

拿出'。' 和“ – ”,如果正整数都是允许的。

用C ++ 11编译器,对于非负整数,我会使用这样的东西(注意::而不是std:: : std::

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

http://ideone.com/OjVJWh

我会build议一个正则expression式的方法。 完整的正则expression式匹配(例如,使用boost :: regex )

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

会显示string是否是数字。 这包括正数和负数,整数以及小数。

其他变化:

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

(只有正面)

 -?[0-9]+ 

(只有整数)

 [0-9]+ 

(只有正整数)

这是使用<regex>库的另一种方法:

 bool is_integer(const std::string & s){ return std::regex_match(s, std::regex("[(-|+)|][0-9]+")); } 

尝试这个:

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

这是一个检查正整数的解决scheme:

 bool isPositiveInteger(const std::string& s) { return !s.empty() && (std::count_if(s.begin(), s.end(), std::isdigit) == s.size()); } 

布伦丹这个

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

几乎没问题

假定任何以0开头的string都是一个数字,只要为这种情况添加一个检查

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

ofc“123hello”会像托尼D指出的那样返回true。

检查一个string是一个整数或浮点数,或者你可以使用:

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

基于kbjorklu评论的解决scheme是:

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

与David Rector的回答一样 ,对于带有多个点或减号的string来说,它是不健壮的,但是您可以删除这些字符来检查整数。


然而,我不太清楚基于Ben Voigt解决scheme的解决scheme ,在cstdlib中使用strtod来查看十进制值,科学/工程符号,hex符号(C ++ 11),甚至是INF / INFINITY / NAN(C ++ 11 )是:

 bool isNumberC(const std::string& s) { char* p; strtod(s.c_str(), &p); return *p == 0; } 

我认为这个正则expression式应该处理几乎所有的情况

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

所以你可以试试下面的函数可以同时使用(Unicode和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 } 
 include <string> 

用于validation双打:

 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; 

}

validationInts(带否定)

 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; 

}

用于validation未签名的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" 

}

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

它是如何工作的: stringstream >> overload可以将string转换为各种不同的算术types,通过从stringstream(本例中为ss)顺序读取字符,直到字符用完,或者下一个字符不符合要存储的条件进入目标variablestypes。

例1:

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

例2:

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

示例3:

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

“垃圾”variables解释“:

为什么不检查是否提取到我的双有一个有效的价值,然后返回true,如果是这样呢?

注意上面的例子3仍然会成功地读取数字11到my_numbervariables中,即使inputstring是“11ABCD”(这不是一个数字)。

为了处理这种情况,我们可以对stringvariables(我命名为垃圾)进行另一次提取,该variables可以读取在初始提取到doubletypesvariables之后可能遗留在string缓冲区中的任何内容。 如果剩下任何东西,它将被读入“垃圾”,这意味着传入的完整string不是一个数字(它只是从一个开始)。 在这种情况下,我们想要返回false;

前面的“0”解释:

试图提取一个单一的字符到一个双将失败(返回0到我们的双),但仍然会移动string缓冲区的位置后面的字符。 在这种情况下,我们的垃圾读取将是空的,这将导致函数错误地返回true。 为了解决这个问题,我在该string前面加了一个0,这样如果传入的string是“a”,它将变成“0a”,这样0将被提取到double中,并且“a”被提取到垃圾中。

预先设置0不会影响数字的值,所以数字仍然会被正确地提取到我们的双variables中。

我的解决scheme使用C ++ 11正则expression式( #include <regex> ),它可以用于更精确的检查,如unsigned intdouble等:

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

你可以在http://ideone.com/lyDtfifind这个代码,这可以很容易地修改,以满足要求。;

正如它在我的相关问题的答案中显示的,我觉得你应该使用boost :: conversion :: try_lexical_convert

我们可能会使用一个stringstream类。

  bool isNumeric(string str) { stringstream stream; double number; stream<<str; stream>>number; return stream.eof(); } 

在查阅了一些文档之后,我想出了一个支持我的需求的答案,但可能不会对其他人有所帮助。 在这里(没有恼人的返回真实并返回错误的陈述:-))

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

几个月前,我实现了一种方法来确定是否有任何string是整数,hex或双精度。

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

然后在你的程序中,你可以很容易地转换它的functiontypes的数字,如果你做以下,

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

您可以认识到,如果没有检测到该号码,该function将返回0。 它可以被视为0(如布尔)。

我提出一个简单的约定:

如果转换为ASCII> 0或以0开始,那么它是一个数字。 这并不完美,但速度很快。

像这样的东西:

 string token0; if (atoi(token0.c_str())>0 || isdigit(token0.c_str()[0]) ) { //this is a value // do what you need to do... } 

我发现下面的代码是最强大的(C ++ 11)。 它捕获整数和浮点数。

 bool isNumber( std::string token ) { using namespace std; return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) ); } 

我能想到的最简单的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; } 

工作代码示例: https : //ideone.com/nRX51Y

还有另外一个答案,即使用stold (尽pipe如果你不需要精度的话也可以使用stof / stod )。

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