Hoe te bepalen of een string een getal is met C++?

Ik heb nogal wat problemen gehad met het schrijven van een functie die controleert of een string een getal is. Voor een spel dat ik aan het schrijven ben, hoef ik alleen maar te controleren of een regel uit het bestand dat ik lees een getal is of niet (op deze manier weet ik of het een parameter is). Ik heb de onderstaande functie geschreven waarvan ik geloof dat deze soepel werkte (of ik heb per ongeluk bewerkt om het te stoppen of ik ben schizofreen of Windows is schizofreen):

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

Antwoord 1, autoriteit 100%

De meest efficiënte manier zou zijn om de tekenreeks te herhalen totdat u een niet-cijferig teken vindt. Als er niet-cijferige tekens zijn, kunt u de tekenreeks niet als een getal beschouwen.

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

Of als je het op de C++11-manier wilt doen:

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

Zoals aangegeven in de opmerkingen hieronder, werkt dit alleen voor positieve gehele getallen. Als u negatieve gehele getallen of breuken moet detecteren, moet u kiezen voor een robuustere bibliotheekgebaseerde oplossing. Hoewel het toevoegen van ondersteuning voor negatieve gehele getallen vrij triviaal is.


Antwoord 2, autoriteit 61%

Waarom opnieuw het wiel opnieuw uitvinden? De C-standaardbibliotheek (ook beschikbaar in C++) heeft een functie die precies dit doet:

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

Als u fracties of wetenschappelijke notatie wilt verwerken, gaat u met in plaats daarvan met strtod(u ontvangt een doubleresultaat).

Als u hexadecimale en octale constanten in C / C++ -stijl ("0xABC") wilt toestaan, maakt u vervolgens de laatste parameter 0.

Uw functie kan dan worden geschreven als

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

Antwoord 3, Autoriteit 29%

Met C++ 11-compiler, voor niet-negatieve gehele getallen zou ik iets dergelijks gebruiken (let op de ::in plaats van std::):

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

http://ideone.com/ojvjWh


Antwoord 4, Autoriteit 19%

U kunt het de C++ doen met BOOST :: Lexical_Cast. Als je er echt bij staat om de boost niet te gebruiken, kun je gewoon onderzoeken wat het doet en dat doen. Het is vrij eenvoudig.

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

Antwoord 5, Autoriteit 11%

Ik zou een reguliere aanpak aanraden. Een volledige regex-overeenkomst (bijvoorbeeld met behulp van boost::regex) met

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

zou laten zien of de tekenreeks een getal is of niet. Dit omvat positieve en negatieve getallen, zowel gehele getallen als decimalen.

Andere varianten:

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

(alleen positief)

-?[0-9]+

(alleen geheel getal)

[0-9]+

(alleen positief geheel getal)


Antwoord 6, autoriteit 10%

Ik wilde gewoon dit idee inbrengen dat iteratie gebruikt, maar een andere code doet die iteratie:

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

Het is niet zo robuust als het zou moeten zijn bij het controleren op een decimaalteken of minteken, omdat er meer dan één van elk en op elke locatie kan zijn. Het goede ding is dat het een enkele regel code is en geen bibliotheek van derden vereist.

Haal de ‘.’ en ‘-‘ als alleen positieve gehele getallen zijn toegestaan.


Antwoord 7, autoriteit 8%

Hier is een andere manier om het te doen met behulp van de <regex>bibliotheek:

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

Antwoord 8, autoriteit 7%

Met deze oplossing kun je alles controleren, van negatieve tot positieve getallen en zelfs zwevende getallen. Als je het type numverandert in integer krijg je een foutmelding als de string een punt bevat.

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

Bewijs: C++-programma


Antwoord 9, autoriteit 7%

Ik heb de volgende code als de meest robuuste gevonden (c++11). Het vangt zowel gehele getallen als floats.

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

Antwoord 10, autoriteit 4%

Probeer dit:

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

Antwoord 11, autoriteit 3%

Hier is een oplossing voor het controleren van positieve gehele getallen:

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

Antwoord 12, autoriteit 2%

Brendan dit

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

is bijna in orde.

ervan uitgaande dat elke tekenreeks die begint met 0 een getal is,
Voeg gewoon een cheque toe voor dit geval

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

ofc “123hello” zal true retourneren zoals Tony D opmerkte.


Antwoord 13, autoriteit 2%

Zoals mij werd onthuld in een antwoordop mijn gerelateerde vraag, vind ik dat u boost::conversion::try_lexical_convert


Antwoord 14, autoriteit 2%

Een oplossing gebaseerd op een commentaar van kbjorkluis:

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

Net als bij Het antwoord van David Rectoris het niet robuust voor tekenreeksen met meerdere punten of mintekens, maar u kunt deze verwijderen tekens om alleen op gehele getallen te controleren.


Ik ben echter voorstander van een oplossing, gebaseerd op Ben Voigt’s oplossing, met behulp van strtodin cstdlib om te kijken naar decimale waarden, wetenschappelijke/technische notatie, hexadecimale notatie (C++11), of zelfs INF/INFINITY/NAN (C++11) is:

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

Antwoord 15, autoriteit 2%

De eenvoudigste die ik kan bedenken in 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;
}

Voorbeeld van werkende code: https://ideone.com/nRX51Y


Antwoord 16, autoriteit 2%

Mijn oplossing die C++11 regex (#include <regex>) gebruikt, kan worden gebruikt voor een nauwkeurigere controle, zoals unsigned int, doubleenz:

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

Je kunt deze code vinden op http://ideone.com/lyDtfi, deze kan eenvoudig worden aangepast om aan de vereisten te voldoen.


Antwoord 17, autoriteit 2%

We kunnen een stringstream-klasse gebruiken.

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

Antwoord 18, autoriteit 2%

Met behulp van <regex>. Deze code is getest!

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

Antwoord 19

Probeer dit:

bool checkDigit(string str)
{  
   int n=str.length();
   for(int i=0;    i   < n ;   i++)
   {
     if(str[i]<'0' || str[i]>'9')
       return false;
   }
   return true;
}

Antwoord 20

C/C++-stijl voor gehele getallen zonder teken, met op bereik gebaseerde forC++11:

int isdigits(const std::string & s)
{
    for (char c : s) if (!isdigit(c)) return (0);
    return (1);
}

Antwoord 21

Na wat meer documentatie te hebben geraadpleegd, kwam ik met een antwoord dat aan mijn behoeften voldoet, maar waarschijnlijk niet zo nuttig zal zijn voor anderen. Hier is het (zonder de vervelende return true en return false statements 🙂 )

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

Antwoord 22

Ik denk dat deze reguliere expressie bijna alle gevallen zou moeten verwerken

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

zodat je de volgende functie kunt proberen die met beide kan werken (Unicode en 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
}

Antwoord 23

include <string>

Voor het valideren van dubbels:

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;

}

Voor het valideren van ints (met negatieven)

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;

}

Voor het valideren van niet-ondertekende int.

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"

}


Antwoord 24

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

hoe het werkt:
de stringstream >> overbelasting kan strings converteren naar verschillende rekenkundige typen
het doet dit door tekens opeenvolgend uit de stringstream te lezen (ss in dit geval) totdat het geen tekens meer heeft OF het volgende teken niet voldoet aan de criteria om te worden opgeslagen in het type bestemmingsvariabele.

voorbeeld1:

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

voorbeeld2:

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

voorbeeld3:

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

de “garbage” variabele verklaring”:

waarom niet gewoon controleren of extractie in mijn double een geldige waarde heeft en dan true retourneren als dat zo is?

let op voorbeeld3 hierboven zal het getal 11 nog steeds met succes inlezen in de my_number variabele, zelfs als de invoerreeks “11ABCD” is (wat geen getal is).

om dit geval af te handelen, kunnen we nog een extractie doen in een stringvariabele (die ik vuilnis heb genoemd) die alles kan lezen dat mogelijk is overgebleven in de stringbuffer na de initiële extractie in de variabele van het type double. Als er iets over is, wordt het in “vuilnis” ingelezen, wat betekent dat de volledige ingevoerde reeks geen nummer was (het begint gewoon met één). in dit geval willen we false retourneren;

de uitleg “0” vooraan”:

Poging om een ​​enkel karakter in een dubbel te halen, mislukt (retourneert 0 in onze dubbele), maar zal de positie van de snaarbuffer nog steeds na het personage verplaatsen. In dit geval is onze afval gelezen leeg die ervoor zorgt dat de functie ten onrechte true retourneert.
Om dit te bereiken, heb ik een 0 naar de string voorgemaakt, zodat als bijvoorbeeld de in de string doormaakte “A” werd veranderd “A” het wordt veranderd in “0A”, zodat de 0 in de dubbele en “A” in vuilnis wordt geëxtraheerd.

Het bijbereiden van een 0 heeft geen invloed op de waarde van het nummer, zodat het nummer nog correct wordt geëxtraheerd in onze dubbele variabele.


Antwoord 25

Controleer of een tekenreeks een getal-integer of een drijvend punt is of dat u kunt gebruiken:

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

Antwoord 26

Nog een ander antwoord, dat stoldgebruikt (hoewel u ook stof/ stodkunt gebruiken als u niet de precisie vereist).

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

Antwoord 27

bool is_number(const string& s, bool is_signed)
{
    if (s.empty()) 
        return false;
    auto it_begin = s.begin();
    if (is_signed && (s.front() == '+' || s.front() == '-'))
        ++it_begin;
    auto non_digit = std::find_if(it_begin, s.end(), [](const char& c) { return !std::isdigit(c); });
    return non_digit == s.end();
}

Antwoord 28

Enkele maanden geleden, heb ik een manier geïmplementeerd om te bepalen of een string geheel getal, hexadecimaal of dubbel is.

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

Vervolgens kun je in je programma het getal gemakkelijk omzetten in functie van het type als je het volgende doet,

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

Je kunt je realiseren dat de functie een 0 retourneert als het nummer niet is gedetecteerd. De 0 kan als onwaar worden behandeld (zoals booleaans).


Antwoord 29

Ik stel een eenvoudige conventie voor:

Als conversie naar ASCII > 0 of het begint met 0 dan is het een getal. Het is niet perfect maar snel.

Zoiets:

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

Antwoord 30

Deze functie zorgt voor alle mogelijke gevallen:

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

Other episodes