如何确定一个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); } 
我会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 int , double等: 
 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); } 
正如它在我的相关问题的答案中显示的,我觉得你应该使用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); }