Ist String eine Zahl?



  • Er will gar nix konvertieren, er will nur wissen obs ne Zahl ist oder nicht.



  • die Funktionen kann man ziemlich einfach selbst programmieren:

    bool IsInteger(const string& input) { return false; }
    bool IsFloat(const string& input) { return false; }
    

    (scnr)



  • Danke das hilft mir wirklich weiter. 🙄



  • Kann mir hier doch noch jemand weiterhelfen? Sitz jetzt schon 11h an dem Projekt. Das Problem besteht aber immer noch.



  • KFlash schrieb:

    Er will gar nix konvertieren, er will nur wissen obs ne Zahl ist oder nicht.

    Trotzdem kannst du über das konvertieren (mit geeigneten Funktionen/Klassen/etc. ("Geeignet" heißt hier = auf Fehler nicht mit der Rückgabe von 0 o.ä. reagieren)) feststellen, ob der String eine Zahl enthält.

    Dies ist der Weg für faule, die sich keine eigene Funktion is...() schreiben möchten (Afaik gibt es nämlich keine derartige Funktion in der Standard-Lib) und bei denen die Leistung für nichts wichtigeres benötigt- oder aber wenn der Zahlentyp später irgendwann noch mal gebraucht wird. :).

    Du kannst eine Funktion is...() für std::strings allerdings sehr einfach selber bauen:

    #include <cctype> // für std::isdigit(int )
    
    bool is_integer(const string& rhs)
    {
        for(size_t i = 0; i < rhs.size(); ++i)
            if(!std::isdigit(rhs[i]))
                return false;
        return true;
    }
    

    (Wobei man hier eventuell noch Over/Underflow-Checks einbauen sollte).

    Gruß Caipi



  • Also ich würde für die Fehlerüberprüfung nicht die "abgespeckten" Funktionen verwenden, die das unterdrücken, sondern die ausführlichere Variante strtod() bzw. strtol() (denen gibst du als zweiten Parameter die Adresse eines char*, in den sie das Ende der erkannten Zahl einspeichern - wenn da was anderes als das Stringende drinsteht, hattest du einen Fehler)



  • #include <string>
    #include <sstream>
    
    ...
    
    bool isInt( const std::string& s)
    {
       std::istringstream iss( s);
       int i;
       return (iss >> i);
    }
    

    Berücksichtigt Vorzeichen, berücksichtigt Locales (Unterschied , und . , Tausender-Trennzeichen), berücksichtigt wissenschaftliche Notation, frisst unnötige Whitespaces. Was will man mehr?

    Will man korrektes Verhalten selber nachbilden, programmiert man sich 'nen Wolf. Und es ist alles schon da. Immer die Bibliotheksfunktionen benutzen, wenn man kann. Die Funktion eignet sich übrigens prima für ein Template.



  • #include <iostream>
    #include <string>
    #include <sstream>
    using namespace std;
    
    bool isInt( const std::string& s)
    {
       std::istringstream iss( s);
       int i;
       return (iss >> i);
    }
    
    int main ()
    {
       cout << isInt("0.5z") << endl;
       cin.get();
    }
    


  • Hm da ist was dran. 😃 Der Parsevorgang sollte eigentlich nicht mit dem nächsten ungültigen Zeichen aufhören.

    bool isInt( const std::string& s)
    {
       std::istringstream iss( s);
       int i;
       if (iss >> i) {
          iss >> std::ws;
          return iss.eof();
       }
       else {
          return false;
       }
    }
    

    Hmm... 5,000 wird trotzdem net erkannt. Wundert/enttäuscht mich ein bisschen von der Funktionalität der Std-Lib.



  • 7H3 N4C3R schrieb:

    Hmm... 5,000 wird trotzdem net erkannt. Wundert/enttäuscht mich ein bisschen von der Funktionalität der Std-Lib.

    Liegt wohl daran, daß für C++ "5,000" keine gültige Zahl darstellt (damit das erkannt wird, müsste man irgendwo die locale's umstellen).



  • CStoll schrieb:

    Liegt wohl daran, daß für C++ "5,000" keine gültige Zahl darstellt (damit das erkannt wird, müsste man irgendwo die locale's umstellen).

    Anscheinend wird das numpunct facet nicht einfach so verwendet, wie ich es jetzt erwartet hätte. Muss ich zuhause mal in Ruhe nachlesen wie das geht. Ich vermute mal es geht, es ist nur ein Verständnisproblem (meinerseits).

    Edit:
    Des Rätsels Lösung: Es liegt tatsächlich an den Locales. Das Standard C Locale sieht kein Tausender-Trennzeichen vor. Schreibt man dagegen zu Programmbeginn z.B. std::locale::global( std::locale( "de_DE")); so wird . als 1000er Trennzeichen benutzt und , als Dezimaltrennzeichen. Leider sind die Locale-Strings nicht standardisiert. 😞



  • Ich will ja nix sagen, aber o.g. Beispiel erkennt bei mir auch "5.000" nicht als Zahl. Wäre evtl. nicht schlecht für Kommazahlen double oder float zu verwenden 😉



  • LordJaxom schrieb:

    Ich will ja nix sagen, aber o.g. Beispiel erkennt bei mir auch "5.000" nicht als Zahl. Wäre evtl. nicht schlecht für Kommazahlen double oder float zu verwenden 😉

    Dann solltest du "5.000" auch nicht in eine Funktion namens isInt stecken. 😉 Und eine Funktion isInt sollte natürlich nicht double oder float verwenden.



  • Moment mal, DU hast unter der Funktion "bool isInt(const std::string&)" geschrieben "Hmm... 5,000 wird trotzdem net erkannt." :p

    Oder meinst Du das , als Tausender-Trennzeichen 😕

    Wahrsager bin ich nicht 😉



  • Hallo Anfänger06

    Anfänger06 schrieb:

    Wie kann ich testen, ob ein gegebener String
    a) eine ganzzahl ist?
    b) eine Fließkommazahl ist?

    bool IsNumber( char * string, bool AcceptFloat )
    {
      if( !string )              // Kein String?
        return false;            // => keine Zahl.
    
      while( *string )           // solange der String nicht zuende ist
      {
        if( *string < '0' || *string > '9' )       // wenn's keine Ziffer ist      // Edit.
          if( *string == '.' && AcceptFloat )      // darfs vielleicht ein Punkt sein?
            AcceptFloat = false;                   // aber höchstens ein Punkt
          else return false;                       // sonst ist es kein gültiges Int/float
    
        string++;                                  // nächstes Zeichen soll geprüft werden
      }
    
      return true;                                 // Der String wurde komplett geparst und es wurden nur gültige Zeichen gefunden.
    }
    

    Ich gehe davon aus, dass es funktioniert, ich hab's nicht getestet.
    EDIT: aus && wurde ||

    In Delphi macht man das per StrToFloat bzw StrToInt. Beide Funktionen werfen eine exception wenn die Konvertierung fehlschlägt.

    Aha... verstehe... macht man das in Delphi so?

    Wenn Du wissen willst, ob an Deinem Auto die Bremsen funktionieren, fährst Du auf die Autobahn, richtig?
    Sollte Dein Leben eine Exception werfen, weißt Du, dass mit diesen Bremsen nicht zu rechnen ist.

    Dieses Vorgehen ist bei manchen Algorithmen schneller - insbesondere, wenn man mit nahezu 100%iger Sicherheit davon ausgehen kann, dass die Bremsen funktionieren. Ich lasse meine Bremsen auch nicht vor jeder Autobahnfahrt prüfen. Aber wenn ich den Verdacht habe, dann finden sich bestimmt andere Möglichkeiten, das zu testen.
    Sogar wenn man Delphi programmiert, kann man es anständig machen.

    Ich habe beide Funktionen in C++ nachgebaut. Nur basieren die auf "atoi" und "atof". Diese Funktionen sind aber unverwüstlich, und liefern einfach 0 wenn was nicht geklappt hat. Das hilft mir nicht weiter, da 0 ja auch bei einer Korrekten eingabe das Ergebnis sein könnte.

    Das ist die richtige Funktionsweise einer Low-Level-Funktion: Übergibt der Programmierer Mist, geht der Mist umgehend an den Absender zurück. Aber eine Low-Level-Funktion meckert nicht, sondern erträgt auch den Anfänger wie ein Mann.

    Gewöhn Dir an, Dinge nur dann zu tun, wenn Du weißt, dass sie funktionieren.
    Das erspart Dir a) die Fehlersuche, wenn Du was programmiert hast und nicht weißt warum Du es so programmiert hast - in C++ solltest Du erst wissen, warum Du etwas schreibst.
    Und es erspart b) die Fehlersuche, wenn irgendwer vergessen hat mit Exceptions nach Dir zu werfen. Da Du wissen solltest, was Du tust, wird in C++ häufig getan, was Du sagst - auch wenn es Unsinn ist.

    Alternativ kann man das auch andersrum aufziehen:
    Ein Programm, das keine Exception wirft berechnet nicht zwangsläufig das, was Du gerne hättest. Also erwarte keine Exception, sondern überlege, wie Du die Funktion garantieren kannst. Daraus ergibt sich, dass Du im Regelfall keine Exceptions benötigst.



  • @Xin: Warum so kompliziert? (außerdem dürfte deine Funktion Probleme mit z.B. 1e10 haben (ja, das ist eine gültige float-Zahl)).

    N4C3R's Lösung lässt sich problemlos auf Gleitkomma-Zahlen umschreiben, indem man statt "int i" einfach "double i" schreibt.

    PS: Als Bonus noch ein Lösungsansatz:

    bool IsNumber(const char* str)
    {
      char* end;
      double d=strtod(str,&end);
      return *end=='\0';
    }
    

Anmelden zum Antworten