Como determinar se uma string é um número com C ++?

Eu tive um pouco de dificuldade tentando escrever uma function que verifica se uma string é um número. Para um jogo que estou escrevendo eu só preciso verificar se uma linha do arquivo que estou lendo é um número ou não (vou saber se é um parâmetro assim). Escrevi a function abaixo que acredito estar funcionando sem problemas (ou eu editei acidentalmente para parar ou sou esquizofrênico ou o Windows é esquizofrênico):

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

   

A maneira mais eficiente seria apenas percorrer a cadeia até encontrar um caractere não digitável. Se houver algum caractere não dígito, você poderá considerar a string não um número.

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

Ou se você quiser fazer o caminho 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(); } 

Como apontado nos comentários abaixo, isso só funciona para inteiros positivos. Se você precisar detectar números inteiros ou frações negativas, você deve ir com uma solução baseada em biblioteca mais robusta. Embora, adicionar suporte a números inteiros negativos é bastante trivial.

Por que reinventar a roda? A biblioteca padrão C (disponível também em C ++) tem uma function que faz exatamente isso:

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

Se você quiser lidar com frações ou notação científica, vá com strtod (você obterá um resultado double ).

Se você quiser permitir constantes hexadecimais e octal no estilo C / C ++ ( "0xABC" ), faça o último parâmetro 0 vez disso.

Sua function então pode ser escrita como

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

Você pode fazer isso da maneira C ++ com boost :: lexical_cast. Se você realmente insistir em não usar boost, você pode apenas examinar o que faz e fazer isso. É bem simples.

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

Com esta solução, você pode verificar tudo, de números negativos a positivos e até mesmo números flutuantes. Quando você altera o tipo de num para inteiro, você receberá um erro se a string contiver um ponto.

 #include #include 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: Programa C ++

Eu só queria lançar essa ideia que usa iteração, mas algum outro código faz essa iteração:

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

Não é robusto como deveria ser ao verificar um ponto decimal ou sinal de menos, pois permite que haja mais de um de cada e em qualquer local. O bom é que é uma única linha de código e não requer uma biblioteca de terceiros.

Retire o ‘.’ e ‘-‘ se inteiros positivos forem todos permitidos.

Com o compilador C ++ 11, para inteiros não negativos eu usaria algo assim (observe o :: vez de std:: :

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

http://ideone.com/OjVJWh

Eu sugeriria uma abordagem de regex. Um full regex-match (por exemplo, usando boost :: regex ) com

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

mostraria se a string é um número ou não. Isso inclui números positivos e negativos, inteiros e decimais.

Outras variações

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

(apenas positivo)

 -?[0-9]+ 

(apenas inteiro)

 [0-9]+ 

(apenas inteiro positivo)

Aqui está outra maneira de fazer isso usando a biblioteca :

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

Tente isto:

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

Aqui está uma solução para verificar inteiros positivos:

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

Brendan esta

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

está quase ok.

assumindo que qualquer string começando com 0 é um número, basta adicionar uma verificação para este caso

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

ofc “123hello” retornará verdadeiro como Tony D notou.

Eu encontrei o seguinte código para ser o mais robusto (c + + 11). Ele captura tanto inteiros quanto flutuantes.

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

Uma solução baseada em um comentário por kbjorklu é:

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

Assim como na resposta de David Rector, ele não é robusto para strings com vários pontos ou sinais de menos, mas você pode remover esses caracteres para apenas verificar inteiros.


No entanto, sou parcial a uma solução, baseada na solução de Ben Voigt , usando strtod em cstdlib para procurar valores decimais, notação científica / engenharia, notação hexadecimal (C ++ 11) ou mesmo INF / INFINITY / NAN (C ++ 11). ) é:

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

Eu acho que essa expressão regular deve lidar com quase todos os casos

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

então você pode tentar a seguinte function que pode trabalhar com ambos (Unicode e 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  

Para validação de duplas:

 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; 

}

Para Validar Ints (com Negativos)

 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; 

}

Para Validar Ints Não-assinados

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

como funciona: o stringstream >> overload pode converter strings para vários tipos aritméticos, ele faz isso lendo caracteres seqüencialmente do stringstream (ss neste caso) até que ele fique sem caracteres OU o próximo caractere não atende aos critérios a serem armazenados no tipo de variável de destino.

Exemplo 1:

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

exemplo2:

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

exemplo3:

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

a explicação da variável “lixo” “:

Por que não apenas verificar se a extração para o meu duplo tem um valor válido e, em seguida, retornar true se isso acontecer?

Observe que o example3 acima ainda lerá com êxito o número 11 na variável my_number, mesmo que a string de input seja “11ABCD” (que não é um número).

Para lidar com este caso, podemos fazer outra extração em uma variável de string (que eu chamei de lixo) que pode ler qualquer coisa que possa ter sobrado no buffer de string após a extração inicial na variável do tipo double. Se sobrou alguma coisa, será lida em “lixo”, o que significa que a cadeia completa passada não era um número (apenas começa com uma). Nesse caso, queremos retornar falso;

a explicação “0” precedente “:

tentar extrair um único caractere em um duplo falhará (retornando 0 em nosso duplo), mas ainda moverá a posição do buffer de string para depois do caractere. Nesse caso, nossa leitura de lixo estará vazia, o que faria com que a function retornasse incorretamente true. Para contornar isso, coloquei 0 na string, de modo que, se, por exemplo, a string passada fosse “a”, ela fosse alterada para “0a”, de forma que o 0 fosse extraído para o dobro e “a” fosse extraído para o lixo.

A prefixação de um 0 não afetará o valor do número, então o número ainda será corretamente extraído em nossa variável dupla.

para verificar se uma string é um número inteiro ou ponto flutuante ou então você pode usar:

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

O mais simples que eu posso pensar em c + +

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

Exemplo de código de trabalho: https://ideone.com/nRX51Y

Minha solução usando C ++ 11 regex ( #include ), pode ser usada para checagem mais precisa, como 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); } 

Você pode encontrar esse código em http://ideone.com/lyDtfi , isso pode ser facilmente modificado para atender aos requisitos.

Como foi revelado para mim em uma resposta à minha pergunta relacionada, eu sinto que você deveria usar boost :: conversion :: try_lexical_convert

Depois de consultar a documentação um pouco mais, encontrei uma resposta que atende às minhas necessidades, mas provavelmente não será tão útil para os outros. Aqui está (sem o retorno irritante verdadeiro e retornar declarações falsas :-))

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

Há alguns meses, eu implementei uma maneira de determinar se alguma string é inteira, hexadecimal ou dupla.

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

Então, no seu programa, você pode facilmente converter o número na function de seu tipo, se fizer o seguinte,

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

Você pode perceber que a function retornará um 0 se o número não foi detectado. O 0 pode ser tratado como falso (como booleano).

Eu proponho uma convenção simples:

Se a conversão para ASCII for> 0 ou começar com 0, então é um número. Não é perfeito, mas rápido.

Algo assim:

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

Ainda outra resposta, que usa stold (embora você também possa usar stof / stod se você não requer a precisão).

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

Podemos usar uma class stringstream .

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

Usando . Este código foi testado!

 bool isNumber(const std::string &token) { return std::regex_match(token, std::regex("(\\+|-)?[0-9]*(\\.?([0-9]+))$")); } 

Esta function cuida de todos os casos possíveis:

 bool AppUtilities::checkStringIsNumber(std::string s){ //Eliminate obvious irritants that could spoil the party //Handle special cases here, eg 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.... }