wake-up-neo.net

Wie kann ich feststellen, ob eine Zeichenfolge eine Zahl mit C++ ist?

Ich hatte ziemlich viele Probleme beim Versuch, eine Funktion zu schreiben, die prüft, ob eine Zeichenfolge eine Zahl ist. Für ein Spiel, das ich schreibe, muss ich nur prüfen, ob eine Zeile aus der Datei, die ich gerade lese, eine Zahl ist oder nicht (ich werde wissen, ob es sich dabei um einen Parameter handelt). Ich schrieb die folgende Funktion, von der ich glaube, dass sie reibungslos funktionierte (oder ich habe sie versehentlich bearbeitet, um sie zu stoppen oder ich bin schizophren oder Windows ist schizophren)

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

    return false;
}
98

Die effizienteste Methode wäre, die Zeichenfolge so lange zu durchlaufen, bis Sie ein Zeichen ohne Ziffer finden. Wenn es keine Ziffern gibt, können Sie die Zeichenfolge nicht als Zahl betrachten.

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

Oder wenn Sie es auf die C++ 11-Weise machen wollen:

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

Wie in den Kommentaren unten ausgeführt, funktioniert dies nur für positive ganze Zahlen. Wenn Sie negative Ganzzahlen oder Brüche erkennen müssen, sollten Sie auf eine robuste, bibliotheksbasierte Lösung zurückgreifen. Das Hinzufügen von Unterstützung für negative Ganzzahlen ist zwar ziemlich trivial.

110
Charles Salvia

Warum das Rad neu erfinden? Die C-Standardbibliothek (auch in C++ verfügbar) verfügt über eine Funktion, die genau dies tut:

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

Wenn Sie mit Brüchen oder wissenschaftlicher Notation umgehen möchten, verwenden Sie stattdessen strtod (Sie erhalten ein double-Ergebnis).

Wenn Sie Hexadezimal- und Oktalkonstanten im C/C++ - Stil ("0xABC") zulassen möchten, nehmen Sie stattdessen den letzten Parameter 0 vor.

Ihre Funktion kann dann als geschrieben werden

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

Mit boost :: lexical_cast können Sie dies auf C++ - Weise tun. Wenn Sie wirklich darauf bestehen, den Boost nicht zu verwenden, können Sie einfach prüfen, was er tut und das tun. Es ist ziemlich einfach.

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

Bei einem C++ 11-Compiler würde ich für nicht negative Ganzzahlen Folgendes verwenden (beachten Sie den :: anstelle von std::):

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

http://ideone.com/OjVJWh

16
szx

Ich wollte nur diese Idee einbringen, die Iteration verwendet, aber ein anderer Code macht diese Iteration:

#include <string.h>

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

Es ist nicht so robust, wie es bei der Suche nach einem Dezimalpunkt oder Minuszeichen sein sollte, da es mehr als einen von jedem und an jedem Ort geben kann. Das Gute ist, dass es sich um eine einzige Codezeile handelt und keine Bibliothek eines Drittanbieters erforderlich ist.

Nimm das '.' und '-', wenn nur positive ganze Zahlen zulässig sind.

13
David Rector

Mit dieser Lösung können Sie alles von negativen bis positiven Zahlen und sogar Float-Zahlen überprüfen. Wenn Sie den Typ von num in Ganzzahl ändern, wird ein Fehler angezeigt, wenn die Zeichenfolge einen Punkt enthält.

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

Beweisen Sie: C++ - Programm

12
tom1991te

Ich würde einen Regex-Ansatz vorschlagen. Eine vollständige Regex-Übereinstimmung (beispielsweise mit boost :: regex ) mit 

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

würde zeigen, ob die Zeichenfolge eine Zahl ist oder nicht. Dies umfasst positive und negative Zahlen, Ganzzahlen sowie Dezimalzahlen.

Andere Variationen:

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

(nur positiv)

-?[0-9]+

(nur ganze Zahl)

[0-9]+

(nur positive ganze Zahl)

11
Mephane

Eine andere Möglichkeit, dies mit der <regex>-Bibliothek zu tun:

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

Ich habe festgestellt, dass der folgende Code der robusteste (C++ 11) ist. Es fängt sowohl Ganzzahlen als auch Schwimmer ab. 

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

Versuche dies:

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

Brendan das

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

ist fast in Ordnung.

angenommen, ein String, der mit 0 beginnt, ist eine Zahl Fügen Sie einfach eine Prüfung für diesen Fall hinzu

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

ofc "123hello" wird wahr zurückgegeben, wie Tony D bemerkt hat.

2
Noam Geffen

Hier ist eine Lösung zum Prüfen positiver Ganzzahlen:

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

Die einfachste, die ich mir in C++ vorstellen kann

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

Arbeitscode-Beispiel: https://ideone.com/nRX51Y

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

wie es funktioniert: Der Stringstream >> overload kann Strings in verschiedene arithmetische Typen konvertieren es liest die Zeichen sequentiell aus dem Stringstream (in diesem Fall ss), bis den Zeichen OR das nächste Zeichen erfüllt nicht die Kriterien, die im Zielvariablentyp gespeichert werden sollen.

beispiel 1:

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

beispiel 2:

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

beispiel3:

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

die "Müll" -Variable "":

Warum nicht einfach prüfen, ob die Extraktion in mein double einen gültigen Wert hat, und dann true zurückgeben, wenn dies der Fall ist?

hinweis Das obige Beispiel 3 liest die Nummer 11 trotzdem erfolgreich in die Variable my_number ein, auch wenn der Eingabe-String "11ABCD" ist (was keine Zahl ist).

um diesen Fall zu handhaben, können wir eine weitere Extraktion in eine String-Variable durchführen (die ich als garbage bezeichnet habe), die alles lesen kann, was nach der anfänglichen Extraktion in den String des Double-Puffers übrig geblieben ist. Wenn etwas übrig bleibt, wird es in "Müll" eingelesen, was bedeutet, dass die gesamte übergebene Zeichenfolge keine Zahl war (sie beginnt nur mit einer). In diesem Fall möchten wir false zurückgeben.

die vorangestellte "0" Erklärung ":

der Versuch, ein einzelnes Zeichen in ein Double zu extrahieren, schlägt fehl (gibt 0 in unser Double zurück), verschiebt jedoch weiterhin die Zeichenfolge des Pufferpuffers nach dem Zeichen. In diesem Fall ist unser Garbage Read leer, was dazu führen würde, dass die Funktion falsch true zurückgibt. Um dies zu umgehen, habe ich der Zeichenfolge eine 0 vorangestellt, sodass die Zeichenfolge geändert wurde, wenn die übergebene Zeichenfolge "a" war "0a", so dass die 0 in das Double und "a" in den Müll extrahiert wird. 

wenn Sie eine 0 voranstellen, wirkt sich dies nicht auf den Wert der Zahl aus, sodass die Zahl immer noch korrekt in unsere doppelte Variable extrahiert wird.

1
KorreyD

Wie mir in einer Antwort meiner verwandten Frage offenbart wurde, sollten Sie boost :: conversion :: try_lexical_convert verwenden.

1
NoSenseEtAl

Eine Lösung basierend auf einem Kommentar von kbjorklu ist:

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

Wie bei David Rector's Antwort ist nicht robust gegenüber Zeichenketten mit mehreren Punkten oder Minuszeichen, aber Sie können diese Zeichen entfernen, um nur nach ganzen Zahlen zu suchen.


Ich bin jedoch unschlüssig an einer Lösung, die auf Ben Voigts Lösung basiert und strtod in cstdlib für Dezimalwerte, wissenschaftliche/technische Notation, hexadezimale Notation (C++ 11) oder sogar INF/INFINITY/NAN ( C++ 11) ist:

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

um zu überprüfen, ob eine Zeichenfolge eine ganze Zahl oder ein Gleitkommawert ist, können Sie Folgendes verwenden:

 #include <sstream>

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

Ich denke, dass dieser reguläre Ausdruck fast alle Fälle behandeln sollte

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

sie können also die folgende Funktion ausprobieren, die sowohl mit Unicode als auch mit ANSI funktioniert.

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
}
1
Motaz
include <string>

Für die Validierung von Doubles:

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;

}

Zur Validierung von Ints (mit Negativen)

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;

}

Zur Validierung von nicht signierten 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"

}

1
Erik Nordin

Nachdem ich mir die Dokumentation etwas genauer angesehen hatte, kam ich zu einer Antwort, die meine Bedürfnisse untermauert, für andere aber wahrscheinlich nicht so hilfreich ist. Hier ist es (ohne die nervige Rückkehr wahr und falsche Aussagen zurückgeben :-))

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

Wir können eine stringstream class verwenden. 

    bool isNumeric(string str)
    {
       stringstream stream;                   
       double number;

       stream<<str;
       stream>>number;

       return stream.eof();
    }
0
rashedcs

Meine Lösung mit C++ 11 Regex (#include <regex>), kann für genauere Überprüfungen verwendet werden, wie 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);
}

Sie finden diesen Code unter http://ideone.com/lyDtfi . Dieser kann leicht an die Anforderungen angepasst werden.

0
aniliitb10

Diese Funktion kümmert sich um alle möglichen Fälle:

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....
}
0
Vaibhav Gupta

Vor einigen Monaten habe ich eine Möglichkeit implementiert, um zu bestimmen, ob eine Zeichenfolge eine Ganzzahl, ein Hexadezimalzeichen oder ein Double ist.

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;


}

Dann können Sie in Ihrem Programm die Zahl einfach in Funktion ihren Typ umwandeln, wenn Sie Folgendes tun:

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

Sie können feststellen, dass die Funktion eine 0 zurückgibt, wenn die Nummer nicht erkannt wurde. Die 0 kann als falsch behandelt werden (wie boolean).

0
Jordi Espada

C/C++ - Stil für vorzeichenlose Ganzzahlen mit bereichsbasiertem for C++ 11:

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

Ich schlage eine einfache Konvention vor:

Wenn die Konvertierung nach ASCII> 0 ist oder mit 0 beginnt, handelt es sich um eine Zahl. Es ist nicht perfekt aber schnell.

Etwas wie das:

string token0;

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

<regex> verwenden. Dieser Code wurde getestet!

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

Versuche dies:

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

Eine weitere Antwort, die stold verwendet (obwohl Sie auch stof/stod verwenden könnten, wenn Sie keine Genauigkeit benötigen).

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);
}
0
Tim Angus

Könnten Sie einfach den Rückgabecode von sscanf verwenden, um festzustellen, ob es sich um ein int handelt?

bool is_number(const std::string& s)
{
    int value;
    int result = sscanf(valueStr.c_str(), "%d", &value);
    return (result != EOF && readResult != 0);
}
0
David D