2013-10-28 19 views
6

Ich versuche, eine Hilfsfunktion zu schreiben, die zum Analysieren von Ganzzahlen aus Konfigurationsdateien und von einem textbasierten Protokoll (geschrieben von Computer, nicht von einem Menschen) verwendet werden kann. Ich habe How to parse a string to an int in C++? gelesen, aber die Lösungen dort adressieren nicht alle Probleme. Ich möchte etwas, das wird (von den meisten zu am wenigsten wichtig):Robust Parsing von ganzen Zahlen in C++

  1. Werte außerhalb des Bereichs ablehnen. strtoul und strtoull erreichen dies nicht ganz: Bei einem führenden Minuszeichen wird der Wert "im Rückgabetyp" negiert. So wird "-5" glücklich geparst und gibt 4294967291 oder 18446744073709551611 zurück anstatt einen Fehler zu signalisieren.
  2. Im C-Gebietsschema sein, unabhängig von der globalen Gebietsschemaeinstellung (oder noch besser, geben Sie mir eine Wahl). Wenn es nicht möglich ist, das globale Gebietsschema auf einer Thread-Basis festzulegen, werden strtoul, stoul und boost :: lexical_cast ausgeschlossen, und es bleibt nur istringstream übrig (wo ein Gebietsschema eingefügt werden kann).
  3. Seien Sie einigermaßen streng. Es darf definitiv keinen nachgestellten Müll akzeptieren, und im Idealfall möchte ich auch Leerraum verbieten. Das macht sofort strtol und alles, was darauf basiert, ein wenig problematisch. Es scheint, dass istringstream hier mit noskipws arbeiten und nach EOF suchen kann, obwohl das vielleicht nur ein GCC-Bug ist.
  4. Idealerweise geben Sie etwas Kontrolle, ob die Basis als 10 angenommen werden soll oder aus einem 0 oder 0x Präfix abgeleitet werden soll.

Irgendwelche Ideen zu einer Lösung? Gibt es eine einfache Möglichkeit, die vorhandene Parsing-Maschinerie so einzubetten, dass sie diese Anforderungen erfüllt, oder wird es weniger Arbeit geben, den Parser selbst zu schreiben?

+0

Wenn es von einer Maschine geschrieben wird, warum sind die Werte außerhalb des Bereichs? – andre

+1

klingt wie du dich entwickeln musst. oder finden Sie eine benutzerdefinierte Bibliothek –

+1

@andre Bereich Validierung ist mehr für die Analyse der Konfigurationsdatei (die von einem Menschen geschrieben wird). Es ist jedoch auch ratsam, alle über ein Netzwerk empfangenen Daten zu validieren. –

Antwort

1

Es gibt einige schnelle Hacks, parse als normal (nicht robust) und einige kleine Überprüfungen in der Eingabe (zum Beispiel, wenn eine nicht negative Zahl zu analysieren, überprüfen Sie, dass es kein '-' Zeichen hat).

Der ultimative Test der Robustheit besteht darin, die Ganzzahl in Text umzuwandeln und zu überprüfen, ob der Eingabetext und der Ausgabetext identisch sind. Wenn Sie in der Textversion arbeiten, können Sie Dinge entspannen, indem Sie führende Nullen oder Leerzeichen akzeptieren.

1

Sie wollen grundsätzlich die num_get<char> Facette des C-Gebiets. Es ist etwas kompliziert, siehe this example. Grundsätzlich müssen Sie use_facet<num_get<char,string::iterator> > (locale::classic).get(begin, end, ... , outputValue) anrufen.

+0

Dies ist im Grunde das gleiche wie mit einem istringstream, da dies der Operator >> unter der Haube benutzt. Der Overhead kann zwar reduziert werden, akzeptiert jedoch immer noch negative Werte und umschließt sie. –

+0

@BruceMerry: Es schneidet in der Tat die Overhead; Es ist nicht so, dass es viele verschiedene Implementierungen unter der Haube gibt. Wie für negative Zahlen, überprüfen Sie, ob es Roundtrips: Können Sie die ursprüngliche Zeichenfolge zurück erhalten? – MSalters