如何确定一个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); }