istreams verstehen
-
Salve,
ich probiere gerade etwas mit streams herum und finde eine (vermeintliche) Ungereimtheit:Ich verarbeite testweise die folgenden beiden Strings:
"0,24 5.7"
"0.24 5,7"
und will sie in double - Variablen einlesen.
Erwartungsgemäß bekomme ich beim ersten String eine 0 und dann fail, und beim zweiten String 0.24, dann 5 und dann fail.Interessant wird es, wenn ich die locales-Eigenschaft des Streams abändere, so dass er das ',' als Dezimalpunkt erkennt.
Nun bekomme ich beim ersten String erwartungsgemäß 0.24 - dann aber NICHT erwartungsgemäß fail UND eof. Erwartet hätte ich analog zum ersten Beispiel, dass ich noch eine 5 und dann fail (nicht aber eof) bekomme.
Beim zweiten String bekomme ich nun sofort fail, erwartet hätte ich, dass ich die 0 bekomme.Offensichtlich verhält sich der Stream völlig anders, wenn man die locales verändert, oder übersehe ich etwas?
Testprogramm:
#include <sstream> #include <string> #include <iostream> #include <locale> using namespace std; int main() { string in_1("0,24 5.7"); string in_2("0.24 5,7"); stringstream numbers(in_1); double tmp; cout << "***\n"; while(numbers >> tmp) cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << " " << tmp << '\n'; cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << '\n'; cout << "***\n"; cout << "* ---- *\n"; numbers.str(in_2); numbers.clear(); cout << "***\n"; while(numbers >> tmp) cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << " " << tmp << '\n'; cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << '\n'; cout << "***\n\n\n"; numbers.str(in_1); numbers.clear(); locale mylocale(""); numbers.imbue( mylocale ); cout << "***\n"; while(numbers >> tmp) cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << " " << tmp << '\n'; cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << '\n'; cout << "***\n"; cout << "* ---- *\n"; numbers.str(in_2); numbers.clear(); cout << "***\n"; while(numbers >> tmp) cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << " " << tmp << '\n'; cout << numbers.good() << numbers.bad() << numbers.fail() << numbers.eof() << '\n'; cout << "***\n\n\n"; }
-
Belli schrieb:
Offensichtlich verhält sich der Stream völlig anders, wenn man die locales verändert, oder übersehe ich etwas?
Hallo Belli,
natürlich verhält sich ein Stream anders, wenn man ihm ein anderes locale unterschiebt, aber nicht unbedingt was die Behandlung von EOF angeht.
Übersehen hast Du was, und zwar die Tatsache, dass außer dem Dezimaltrenner in einer Fließkommazahl noch weitere Zeichen auftreten können, die keine Ziffern sind.Ändere die Zeilen 11 und 12 nach
string in_1("10,240 5.700"); string in_2("10.240 5,700");und schaue Dir das Ergebnis an. Ich bin sicher, dass Dir dann sofort auffällt, was dort passiert ist.
Prosit Neujahr
Werner
-
Auf eine Antwort von Dir habe ich gehofft!
Ja, nun sehe ich es: Der '.' wird nach Umstellung der locales nicht sofort als ungültig erkannt, weil er ein Tausendertrennzeichen sein könnte ...
Da wäre ich so schnell (eher gar) nicht drauf gekommen!
Danke schön!Jetzt wundert mich nur noch ein wenig, dass ohne Umstellung nicht das ',' als Tausendertrennzeichen interpretiert wird ... aber auf jeden Fall hast Du mich erwartungsgemäß ein wenig erleuchtet!
Frohes Neues Jahr!
Edit:
Ach doch, ohne locales kein Tausendertrennzeichen, wenn man explizit auf US umstellt, dann dürfte das ',' wohl entsprechend interpretiert werden ... werde ich gleich mal austesten ...
-
Belli schrieb:
Jetzt wundert mich nur noch ein wenig, dass ohne Umstellung nicht das ',' als Tausendertrennzeichen interpretiert wird ...
.. das ist ein ganz heißes Thema. Suche mal in der newsgroup microsoft.public.vc.stl nach "numpunct Plauger Werner" (Link habe ich leider keinen). Dort findest Du einen Thread vom Januar 2007, in dem ich ein Verhalten im damals neuen Visual Studio 8 beim Einlesen von int-Variablen mit nachgestelltem Komma schildere, was in einem real existierenden Format zu einem Lesefehler führt. Das Problem wurde dann mit dem Service Pack 1 behoben.
Der Herr Plauger war leider sehr zurückhaltend bei der Schilderung der Gründe für dieses Feature (oder Bug!). Aus heutiger Sicht gehe ich davon aus, dass das ',' in realen Formaten viel zu häufig als Trennzeichen verwendet wird (z.B auch das csv-Format von MS-Excel - csv steht für 'comma separated values'), als dass man es als Tausendertrennzeichen für Zahlen interpretieren darf.
Selbst die englische Wiki-Seite zu CSV schildert bereits im ersten Absatz dieses Problem.Gruß
Werner
-
Ein ähnliches Problem hatte ich gerade bei der Compilierung eines Programmes mit wxWidgets. Die Beispieldateien wurden vom XML-Parser falsch interpretiert, da es sich herausgestellt hat, dass der numerische Punkt als "," definiert war.
Abgesehen davon, dass wx seine eigene wxLocale-Klasse mitbringt, ein einfaches setlocale(LC_ALL, "C"); beim Applikationsstart war ein schneller Workaround.
Aber - was hier genau geschieht - darüber gibt es verdammt wenig Information.