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


136

Ich hatte einige 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 überprüfen, ob eine Zeile aus der Datei, die ich lese, eine Zahl ist oder nicht (ich werde wissen, ob es sich auf diese Weise um einen Parameter handelt). Ich habe die folgende Funktion geschrieben, von der ich glaube, dass sie reibungslos funktioniert (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;
}

184
Ich hasse es zu sehen if (expr) return true; return false;! Schreib einfach return expr;.
Ephemient

17
@ephemient Mein Stil ist es, dasselbe zu tun wie Sie. Aber ist es wirklich eine große Sache?
Brennan Vincent

2
Ihr Funktionsprototyp scheint nicht angemessen zu sein. Warum nicht bool isParam (const string & line) verwenden
MikimotoH

4
Ja. Ich habe die schlechte Angewohnheit, beim Erlernen einer neuen Sprache Long-Style zu programmieren. Ich bin neu in C ++ und zögere eher mit "Verknüpfungen" (oder wahrgenommenen Verknüpfungen).
Brendan Weinstein

57
@Brennan Vincent: Ja, das ist eine große Sache. Es ist die gleiche Klasse von Fehlern , wie if (expr) return expr; else return expr;, if (expr == true), (if expr != false)oder if ((expr == true) == true). Sie alle führen zu einer Komplexität, die dem Verfasser, Leser oder Compiler des Codes nicht zugute kommt. Die Beseitigung unnötiger Komplexität ist keine Abkürzung. Es ist der Schlüssel zum Schreiben besserer Software.
MSalters

Antworten:


147

Der effizienteste Weg wäre, einfach über die Zeichenfolge zu iterieren, bis Sie ein nichtstelliges Zeichen finden. Wenn nichtstellige Zeichen vorhanden sind, können Sie die Zeichenfolge als keine 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 C ++ 11-Weise tun möchten:

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

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 sich für eine robustere bibliotheksbasierte Lösung entscheiden. Das Hinzufügen von Unterstützung für negative Ganzzahlen ist jedoch ziemlich trivial.


6
Behandelt auch keine negativen und nicht ganzen Zahlen. Wir können nicht wissen, welche Anforderungen auf der Frage basieren.
Brennan Vincent

76
Sie können auch !s.empty() && s.find_first_not_of("0123456789") == std::string::npos;einen C ++ 03-Einzeiler verwenden.
kbjorklu


3
@Remy Lebeau, ja, das tut es. Es konvertiert den String nicht in einen int. Es wird nur identifiziert, ob eine Zeichenfolge aus numerischen Ziffern besteht. Es spielt keine Rolle, wie lang die Zeichenfolge ist.
Charles Salvia

5
Vergessen Sie nicht , das C ++ 11-Beispiel einzuschließen <string> <algorithm>und <cctype>zum Laufen zu bringen.
KR105

88

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, wählen strtodSie stattdessen (Sie erhalten ein doubleErgebnis).

Wenn Sie hexadezimale und oktale Konstanten im C / C ++ - Stil ( "0xABC") zulassen möchten, geben Sie 0stattdessen den letzten Parameter ein.

Ihre Funktion kann dann geschrieben werden als

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

4
Diese Funktion verwirft Leerzeichen vor. Sie müssen also das erste Zeichen auf isdigit prüfen.
Chmike

1
@chmike: Nach meinem Verständnis der Frage ist das Verwerfen führender Leerzeichen das richtige Verhalten ( atoiwie in der Frage auch).
Ben Voigt

1
Die Frage hat es nicht explizit angegeben, aber mein Verständnis der Anforderung "prüft, ob eine Zeichenfolge eine Zahl ist" bedeutet, dass die gesamte Zeichenfolge die Zahl ist, also keine Leerzeichen. Ich hatte das Bedürfnis, darauf hinzuweisen, dass sich Ihre Antwort in dieser Hinsicht von den anderen unterscheidet. Ihre Antwort kann in Ordnung sein, wenn die Zeichenfolge vor der Zahl Leerzeichen enthält.
chmike

1
@ BenVoigt Du sagst, das pwird eingestellt, nullptrwenn strtoles erfolgreich ist, oder? Das sehe ich nicht :(
Jonathan Mee

2
@JonathanMee: Nein, pwird den NUL werden zeigen, die die Zeichenfolge beendet. Also p != 0und *p == 0.
Ben Voigt

33

Mit dem C ++ 11-Compiler würde ich für nicht negative Ganzzahlen so etwas verwenden (beachten Sie das ::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


1
Dies ist die beste Antwort.
Martin Broadhurst

Wenn die Zeichenfolge utf8-Zeichen enthält, wird ein Laufzeitfehler angezeigt.
König der Löwen

29

Sie können dies auf C ++ - Weise mit boost :: lexical_cast tun. Wenn Sie wirklich darauf bestehen, Boost nicht zu verwenden, können Sie einfach untersuchen, was es 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 }

21
Mit try{} catch{}einer guten Idee? Sollten wir es nicht so weit wie möglich vermeiden?
Nawaz

32
-1 für Missbrauch versuchen fangen ... blogs.msdn.com/b/ericlippert/archive/2008/09/10/…
NoSenseEtAl

14
try {} catch {} ist hier angebracht. Fang (...) ist jedoch nur eine schlechte Praxis. Verwenden Sie in diesem Fall boost :: bad_lexical_cast für Ihren Ausnahmebehandler.
NuSkooler

5
Ich habe das Gefühl, dass dies versucht, aus einer Datei zu lesen. Egal wie viel Sie an der Datei überprüfen, Sie werden nicht wissen, ob es möglich ist, daraus zu lesen, bis Sie es tun. Es wird entweder funktionieren oder nicht. In diesem Fall müssen Sie eine Ausnahme abfangen. In diesem Fall denke ich, dass dies eine völlig gute Möglichkeit ist, dies zu tun.
Casey

4
@EarlGray - Ich wäre sicherlich daran interessiert zu hören, welche betriebssystemabhängigen Aktionen Windows ausführen würde. Der Standard ist ziemlich klar darüber, wie sich dieser Code verhalten soll.
Edward Strange

16

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 sein sollte, wenn nach einem Dezimalpunkt oder einem Minuszeichen gesucht wird, da es an jedem Ort mehr als einen von jedem geben kann. Das Gute ist, dass es sich um eine einzelne Codezeile handelt und keine Bibliothek eines Drittanbieters erforderlich ist.

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


Fehler: 'strspn' wurde in diesem Bereich nicht deklariert. Ich denke, das liegt daran, dass mir ein "#include" fehlt, aber welches
Qwertie

4
Wenn Sie verwenden möchten std::string, verwenden Sie die find_first_not_ofMember-Funktion.
Ben Voigt

5
Dies würde fehlschlagen, wenn Sie eine Zeichenfolge von "12.3-4.55-" übergeben, was offensichtlich keine gültige Zahl ist
Buzzrick

Buzzrick, die vorgeschlagene Antwort besagt bereits, dass dies mit der von Ihnen genannten Nicht-Nummer fehlschlagen würde.
David Rector

Wenn Sie es nur auf "0123456789" beschränken, ist die Formel perfekt, um auf vorzeichenlose Ganzzahlen zu testen
niemand spezielles

16

Ich würde einen Regex-Ansatz vorschlagen. Eine vollständige Regex-Übereinstimmung (z. B. 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)


Ähm, ich habe versucht, std::regexmit gcc 4.7, gcc 4.8 zu verwenden - beide werfen std::regex_errorjedes Zeichen von [Regexp auf, selbst für ein unschuldiges "[abc]" (mache ich das falsch?). clang-3.4 ist sich dessen überhaupt nicht bewusst <regex>. Auf jeden Fall scheint dies die vernünftigste Antwort zu sein, +1.
Dmytro Sirenko

3
@EarlGray: Regex ist nur von GCC 4.9
Lightness Races in Orbit

13

Hier ist eine andere Möglichkeit, dies mithilfe der <regex>Bibliothek zu tun :

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

Ah, so würde es sein. Ich habe mit einer besseren Lösung aktualisiert. Vielen Dank.
mpataki14

Sollte es nicht "[(- | +) |] [0-9] +" (Plus anstelle von Stern) sein, könnte Ihre Regex mit "-" oder "+" als gültige Zahl übereinstimmen.
David Mulder

Nett. Ich bin mir nicht sicher, was die (, | und) in dieser ersten Zeichenklasse tun - diese Metazeichen verlieren, soweit mir bekannt ist, ihre besondere Bedeutung innerhalb einer Zeichenklasse. Wie wäre es mit "^ [- +]? [0-9] + $"?
U007D

Es kann ineffizient sein. Bei jedem Aufruf wird der Konstruktor std :: regex aufgerufen, der den regulären Ausdruck kompiliert.
user31264

12

Mit dieser Lösung können Sie alles von negativen über positive Zahlen bis hin zu Gleitkommazahlen überprüfen. Wenn Sie den Typ von numin eine Ganzzahl ändern , wird eine Fehlermeldung 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


10

Ich habe festgestellt, dass der folgende Code am robustesten ist (c ++ 11). Es fängt sowohl ganze Zahlen als auch Floats ab.

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

Es scheint, dass die Linie using namespace std;unnötig ist.
Xam

5

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

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

5

Versuche dies:

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

1
Dies testet nur für vorzeichenlose ganze Zahlen
niemand spezielles

4

Brendan das

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

ist fast ok

Angenommen, eine Zeichenfolge, die mit 0 beginnt, ist eine Zahl. Fügen Sie für diesen Fall einfach eine Prüfung hinzu

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

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


3

Das einfachste, was 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;
}

Beispiel für einen Arbeitscode : https://ideone.com/nRX51Y


3

Meine Lösung unter Verwendung von C ++ 11 regex ( #include <regex>), kann es für eine genauere Überprüfung verwendet werden, wie unsigned int, doubleetc:

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 . Er kann leicht geändert werden, um den Anforderungen zu entsprechen.


Ich würde Downvoter bitten, mir zu helfen, das Problem zu verstehen. Ich werde meine Antwort verbessern. Vielen Dank.
Aniliitb10

2

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 der Antwort von David Rector ist es nicht robust gegenüber Zeichenfolgen mit mehreren Punkten oder Minuszeichen, aber Sie können diese Zeichen entfernen, um nur nach Ganzzahlen zu suchen.


Ich bin jedoch Teil einer Lösung, die auf der Lösung von Ben Voigt basiert und strtodin cstdlib Dezimalwerte, wissenschaftliche / technische Notation, hexidezimale Notation (C ++ 11) oder sogar INF / INFINITY / NAN (C ++ 11) verwendet. ist:

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

2

Wir können eine Stringstream- Klasse verwenden.

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

       stream<<str;
       stream>>number;

       return stream.eof();
    }

2

Verwenden von <regex>. Dieser Code wurde getestet!

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

1

Nachdem ich die Dokumentation etwas genauer durchgesehen hatte, fand ich eine Antwort, die meine Bedürfnisse unterstützt, aber für andere wahrscheinlich nicht so hilfreich ist. Hier ist es (ohne die nervige Rückkehr wahr und falsche Aussagen zurückzugeben :-))

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

4
Wenn die Zahl zufällig ist 0, erhalten Sie ein falsch-negatives Ergebnis.
Charles Salvia

3
Dies gibt eine führende Nummer zurück und warnt Sie nicht vor nachlaufendem Müll (z. B. "123hello" ==> 123). @ Charles: Brendan erwähnt, dass er nur positive Ints in einem Kommentar zu einer anderen Antwort erkennen muss.
Tony Delroy

1

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

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

Sie können also die folgende Funktion ausprobieren, die mit beiden funktioniert (Unicode und 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
}

1
include <string>

Zur Validierung von Doppel:

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;

}}

Zum Validieren von Ints ohne Vorzeichen

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

So funktioniert es: Die Überladung von stringstream >> kann Zeichenfolgen in verschiedene arithmetische Typen konvertieren. Dazu werden Zeichen nacheinander aus dem Zeichenfolgenstrom (in diesem Fall ss) gelesen, bis die Zeichen ausgehen oder das nächste Zeichen die zu speichernden Kriterien nicht erfüllt in den Zielvariablentyp.

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

Beispiel 3:

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

die "Müll" -Variablenerklärung ":

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?

Beachten Sie, dass Beispiel 3 oben die Nummer 11 weiterhin erfolgreich in die Variable my_number einliest, selbst wenn die Eingabezeichenfolge "11ABCD" ist (was keine Nummer ist).

Um diesen Fall zu behandeln, können wir eine weitere Extraktion in eine Zeichenfolgenvariable (die ich Garbage nannte) durchführen, die alles lesen kann, was nach der anfänglichen Extraktion in die Variable vom Typ double im Zeichenfolgenpuffer übrig geblieben ist. Wenn noch etwas übrig ist, wird es in "Garbage" eingelesen, was bedeutet, dass die übergebene vollständige 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 (0 in unser Double zurück), verschiebt jedoch die Position des Zeichenfolgenpuffers nach dem Zeichen. In diesem Fall ist unser Garbage Read leer, was dazu führen würde, dass die Funktion fälschlicherweise true zurückgibt. Um dies zu umgehen, habe ich der Zeichenfolge eine 0 vorangestellt, sodass, wenn beispielsweise die übergebene Zeichenfolge "a" war, diese in "0a" geändert wird, sodass die 0 in das Double und "a" in den Müll extrahiert wird.

Das Voranstellen einer 0 hat keinen Einfluss auf den Wert der Zahl, sodass die Zahl weiterhin korrekt in unsere Doppelvariable extrahiert wird.


1
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Ajean

1

Um zu überprüfen, ob eine Zeichenfolge eine Ganzzahl oder ein Gleitkomma 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
Dies gibt 10 für eine Zeichenfolge zurück, die den Wert "10_is_not_a_number" enthält.
KorreyD

1

Noch eine andere Antwort, die verwendet stold(obwohl Sie auch verwenden könnten stof/ stodwenn Sie nicht die Präzision 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);
}


1

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

1

Mit boost :: lexical_cast können Sie testen, ob eine Zeichenfolge in eine Ganzzahl konvertierbar ist . Wenn die Ausnahme bad_lexical_cast ausgelöst wird, konnte der String nicht konvertiert werden, andernfalls kann er konvertiert werden.

Siehe Beispiel eines solchen Testprogramms unten:

#include <boost/lexical_cast.hpp>
#include <iostream>

int main(int, char** argv)
{
        try
        {
                int x = boost::lexical_cast<int>(argv[1]);
                std::cout << x << " YES\n";
        }
        catch (boost::bad_lexical_cast const &)
        {
                std:: cout << "NO\n";
        }
        return 0;
}

Beispielausführung:

# ./a.out 12
12 YES
# ./a.out 12/3
NO

0

Vor einigen Monaten habe ich eine Methode implementiert, um festzustellen, ob eine Zeichenfolge eine Ganzzahl, eine Hexadezimalzahl oder eine Doppelzeichenfolge 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 die Funktion ihres Typs konvertieren, 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 boolesch).


0

Ich schlage eine einfache Konvention vor:

Wenn die Konvertierung in 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

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

Könnten Sie einfach den Rückkehrcode 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);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.