String auf Ziffern prüfen


  • Mod

    @Finnegan sagte in String auf Ziffern prüfen:

    Gibt es bei diesen steinalten Char-Funktionen tief in der C-Standardbibliothek eigentlich irgendwo auch etwas, was diesen int-Parameter rechtfertigt? Irgend ein altertümliches Fehler-Handling, wo negative Zahlen Fehlercodes sind oder sowas? Im '<cctype>'-Header seh ich auf en ersten Blick nichts dergleichen.

    Soll das nicht EOF als Parameter ermöglichen?


  • Mod

    @Finnegan sagte in String auf Ziffern prüfen:

    Ja, die berühmt-berüchtigten C++-Altlasten. Solche Funktionen würde man heute jedem Anfänger um die Ohren hauen, wenn er sowas abliefern würde 😉 . Gibt es bei diesen steinalten Char-Funktionen tief in der C-Standardbibliothek eigentlich irgendwo auch etwas, was diesen int-Parameter rechtfertigt? Irgend ein altertümliches Fehler-Handling, wo negative Zahlen Fehlercodes sind oder sowas? Im '<cctype>'-Header seh ich auf en ersten Blick nichts dergleichen.

    Es geht um die EOF-Signalisierung, geerbt von C, und nie benutzt seit es Streams (mit Eof-Flag) gibt. Aber in C wird damit im Rückgabewert von Zeichenlesefunktionen signalisiert, dass ein Lesefehler aufgetreten ist. Und das ist meistens so etwas wie -1 um Konflikte mit regulären Zeichen zu vermeiden. Die Anleitung von isdigit sagt ja auch explizit, dass das Verhalten trotz negativer Werte nicht undefiniert ist, falls das Zeichen gleich dem EOF-Sonderwert ist.



  • Danke. Und Btw. witzig, was für Diskussionen hier immer wieder durch unschuldige Anfängerfragen losgetreten werden. Da weiss @Johnny01 gleich auf was er sich in Zununft alles gefasst machen muss, wenn er sich auf eine Sprache wie C++ einlässt 👍 ... da kann hinterher niemand sagen, er hätte nicht gewusst, was da auf einen zurollt 😉


  • Mod

    @Finnegan sagte in String auf Ziffern prüfen:

    Danke. Und Btw. witzig, was für Diskussionen hier immer wieder durch unschuldige Anfängerfragen losgetreten werden. Da weiss @Johnny01 gleich auf was er sich in Zununft alles gefasst machen muss, wenn er sich auf eine Sprache wie C++ einlässt 👍 ... da kann hinterher niemand sagen, er hätte nicht gewusst, was da auf einen zurollt 😉

    Sehr wahrscheinlich braucht er das, was hier gefragt ist, ja nicht wirklich. Das ist entweder eine Übungsaufgabe "prüfen Sie auf Ziffern", die man nie wieder braucht, oder es ist eine Vorstufe dazu, das Rad selber neu erfinden (also, dass das später mal Zahlen parsen soll oder so), was man generell nicht machen sollte. Denn das man isdigit in high-level Anwendungscode braucht dürfte echt selten sein. Und wenn man meint, low-level IO-Bibliotheken selber neu erfinden zu müssen, dann ist dies eines der geringsten Probleme, auf die man stoßen wird.



  • BTW: Der ganze Ärger hätte sich auch vermeiden lassen. Wenn man EOF z.B. mit -129 oder auch einfach -200 festlegt hat man auf 8-Bit char Systemen kein Problem (mit CHAR_BIT != 8 braucht man halt entsprechend andere Werte). Man hätte also ohne weiteres definieren können dass man char, signed char und unsigned char Werte 1:1 da reinschieben kann ohne UB oder ein falsches Ergebnis zu bekommen.


  • Mod

    @hustbaer Es ist der Standard, der festlegt dass die Klassifizierungsfunktionen nur auf unsigned char Range definiert sind. Der Standard hat EOF nicht als -1 festgelegt, u.a. aus dem Grund, den du selber suggerierst, dass die Range von char-Typen nicht festgelegt wird. Du musst schon vorschlagen, wie der Standard, ohne solche Annahmen zu machen, das Problem lösen kann. Der Standard würde ja dadurch, dass er isalnum etc. mit char Range erlaubt, die Implementierung zwingen, EOF so festzulegen wie Du vorschlägst (d.h. -1 wäre nur bedingt zulässig). Dann haben wir plötzlich X verschiedene EOF Werte je nach Compiler/Platform. 🤮

    Edit^2:
    Oder "alle" einigen sich darauf, EOF mit irgendeinem genügend kleinen Wert zu belegen. von CHAR_BIT > 16 habe ich nicht gehört, aber das schliesst nicht aus, dass es das irgendwann geben wird, oder gegeben hat. Der Koordinierungsaufwand ist diese paar Funktionen hier gar nicht wert. Und dann sind die Systeme, auf denen CHAR_BIT == 16 ist, manchmal auch noch sizeof(int) == 1. Dann ist zwar EOF == -1 gültig, weil man char als vorzeichenlos definiert, aber 2161-2^{16}-1 nicht mehr.... Das heisst, das Problem lässt sich nicht einheitlich lösen, wenn es sowohl ein System mit 16 Bit (unsigned) char/int gibt, als auch 16 bit signed char/32 bit int? Or am I missing something?

    KIar haette man auf POSIX deinen Vorschlag berücksichtigen können. Aber -1 ist als universeller Wert keine schlechte Wahl IMHO.
    Edit: Ich glaub nicht, dass die Platform als Annahme reicht. Es wäre einfach unbesonnen, EOF in irgendeiner Weise zu parametrisieren. Der Wert wird in so vielen Ecken verwendet, z.B. in LUTs, dass es deutlich simpler ist, einfach einen universalen Wert zu wählen, anstatt einen platformabhaengigen.



  • Wie würde man denn heute im modernen C++ einzelne Zeichen eines Strings darauf testen ob sie eine Ziffer sind oder nicht?


  • Mod

    @CppConst sagte in String auf Ziffern prüfen:

    Wie würde man denn heute im modernen C++ einzelne Zeichen eines Strings darauf testen ob sie eine Ziffer sind oder nicht?

    Die Frage ist nicht wie, sondern warum. Warum denkst du das in modernem C++ zu brauchen?



  • @CppConst sagte in String auf Ziffern prüfen:

    Wie würde man denn heute im modernen C++ einzelne Zeichen eines Strings darauf testen ob sie eine Ziffer sind oder nicht?

    Das würde man so machen:

    #include <ctre.hpp>
    bool string_of_digits(std::string_view sv) { 
        return ctre::match<"^[0-9]+$">(sv);
    }
    

    An sowas wie if (ch >= '0' && ch <= '9') würde ich heutzutage keine Gedanken mehr verschwenden!


  • Mod

    Regexmatches um eine Simpelabfrage zu ersetzen? Da fehlt noch, dass du einen Container auf einer VM startest, die mit dem String einen Webservice fragt, woraus der String besteht und das ergebnis in einer Blockchain speichert.


  • Mod

    @SeppJ sagte in String auf Ziffern prüfen:

    Regexmatches um eine Simpelabfrage zu ersetzen? Da fehlen noch mindestens 3 Webservices die du fragen musst und irgendwo muss noch eine Blockchain rein.

    Ich vermute stark, dass ctre constexpr ist, und die Konstruktion des DFAs zur Compilezeit geschieht.
    Edit: ja, es ist natuerlich immer noch overengineered, lol. Ich dachte du beziehst Dich auf die Performance



  • @SeppJ sagte in String auf Ziffern prüfen:

    Die Frage ist nicht wie, sondern warum. Warum denkst du das in modernem C++ zu brauchen?

    Weil man die Tests nicht mehr mit C Code machen will? Ich hatte vor etlichen Jahren das Problem, dass ich eine Plattform unabhängige Version (d.h. unabhängig von der locale Einstellungen des OS) dafür brauchte, so hatte ich das mit 8Bit Char (UNIX) geschrieben. Das Programm hat hauptsächlich Texte verarbeitet und in eine DB abgelegt.



  • Genau, wenn ich dieses Aufgabe der Ziffernerkennung habe, dann möchte ich gern wissen wie man das im modernen C++ macht und nicht mit C-Methoden.

    Ist das daher keine legitime und logische Frage?
    @SeppJ sagte in String auf Ziffern prüfen:

    @CppConst sagte in String auf Ziffern prüfen:

    Wie würde man denn heute im modernen C++ einzelne Zeichen eines Strings darauf testen ob sie eine Ziffer sind oder nicht?

    Die Frage ist nicht wie, sondern warum. Warum denkst du das in modernem C++ zu brauchen?

    Keine Ahnung ich lese eine Textdatei ein und will wissen ob da Zahlen mit drin sind zum Beispiel. Oder ich lese von einem Textfeld einer GUI was ein und will wissen ob da ne Zahl mit drin ist. Gibt doch sicher viele Beispiele wo es interessant wird zu wissen ob da ne Zahl oder mehrere drin sind.


  • Mod

    @CppConst sagte in String auf Ziffern prüfen:

    Keine Ahnung ich lese eine Textdatei ein und will wissen ob da Zahlen mit drin sind zum Beispiel. Oder ich lese von einem Textfeld einer GUI was ein und will wissen ob da ne Zahl mit drin ist. Gibt doch sicher viele Beispiele wo es interessant wird zu wissen ob da ne Zahl oder mehrere drin sind.

    In der Praxis haben Eingabefelder einen bestimmten Zweck, d.h. sie sollen eine Zahl enthalten (und nicht enthalten können). Im Code würdest Du dann eine Funktion aufrufen, die diese Zahl auslesen soll. Im Falle eines Fehlers signalisiert die Funktion das entsprechend. D.h. nicht

    if (!isnumber(field)) {
        bark
    } else {
       n = readnum(field);
       ...
    }
    

    schreiben, sondern

    int n
    if (!readnum(field, &n)) {
        bark
    }
    ...
    

    Wenn Du readnum selbst implementieren möchtest, nur zu, aber ich habe noch nie eine Funktion gebraucht/gesehen, die einen String auf eine Zahl nur prüft, anstatt sie gleichsam zu extrahieren.



  • @Columbo sagte in String auf Ziffern prüfen:

    readnum

    Ich möchte nichts implementieren was schon da ist: readnum gehört zum Standard C++?


  • Mod

    @CppConst "readnum" ist gleich std::cin >> n



  • Wenn's darum geht Ziffern zu erkennen...

    Man kann z.B. https://en.cppreference.com/w/cpp/locale/ctype_char verwenden.
    Wenn's locale-abhängig funktionieren soll kann man auch die ctype facet der aktuellen locale verwenden: https://en.cppreference.com/w/cpp/locale/ctype

    Wenn's OK ist sich auf Zeichensätze festzulegen bei denen die Codes von 0...9 fortlaufend sind (was OK sein sollte), kann man auch nach wie vor ch >= '0' && ch <= '9' schreiben.
    Wenn's etwas schneller sein soll kann man auch size_t(ch) - size_t('0') <= 9 schreiben.



  • @Columbo sagte in String auf Ziffern prüfen:

    @CppConst "readnum" ist gleich std::cin >> n

    Oder from_chars: https://en.cppreference.com/w/cpp/utility/from_chars
    (Oft besser wenn der Code auch schnell sein soll und der Input nicht sowieso schon in einem Stream steht.)


  • Mod

    @hustbaer Ups. Klar, wenn man einen String hat. Ich dachte irgendwie unbewusst an stdin. 🙂



  • Vielen Dank, was es nicht alles gibt und man wenig findet wenn man danach sucht. Modernes C++ lernen ist echt nicht einfach.


Anmelden zum Antworten