Datei zeichenweise auslesen - newline Problem.
-
#include <iostream> using namespace std; int main() { int wert; while (!(cin >> wert).eof()) if (cin) cout << wert << '\n'; else { cin.clear(); cin.ignore(1); } }
-
redrew99 schrieb:
Ok, hatte das aus einem Lehrbuch (Der C++-Programmierer) übernommen.
Lese ich auch gerade. Die Stelle kam bei mir auch vor ein paar Tagen vor und da hatte ich mich schon gefragt, wieso er exit verwendet.Verstehst du die Lösung von SeppJ oder noch Erklärungsbedarf?
-
@SeppJ
Danke, das ist wirklich superkurz
Beim Testen des Programms ist mir etwas aufgefallen:
Ein "-" vor einer Zahl wird nicht als Bindestrich angesehen, sondern als Minuszeichen.
Es wäre nicht schlecht, wenn man das entsprechend einstellen könnte, je nachdem ob es halt negative Zahlen geben soll oder
nicht.Gugelmoser schrieb:
Verstehst du die Lösung von SeppJ oder noch Erklärungsbedarf?
Was ich nicht verstehe ist, warum zusammenhängende Ziffern als Zahl gewertet werden.
Vermutlich ist die entsprechende Klassenfunktion so programmiert, die würde ich mir gerne mal anschauen, hab bei
http://www.cplusplus.com/reference/iostream/istream/ leider nichts dazu gefunden.
-
Ergänzung:
Wenn man bei dem Programm z.B. "--798" o. "+-298" eingibt, wird "798" bzw. "298" ausgegeben.
Das ist irgendwie unlogisch. Entweder wird ein Bindestrich als Minuszeichen angesehen oder halt nicht.
-
Nimm eben unsigned int.
Die Klassenfunktion ist diese:
http://www.cplusplus.com/reference/iostream/istream/operator>>/ (leider scheint die Formatierung auf der Seite nicht in Ordnung zu sein)
Kennst du also sicherlich schon.
-
SeppJ schrieb:
Nimm eben unsigned int.
Hatte ich schon ausprobiert, das geht leider auch nicht.
Bei Eingabe von z.B. "-764" gibt die Konsole "4294966498" aus.Auch cin.ignore(1,'-') habe ich[Edit: separat] probiert, wobei ich nicht genau weiß, ob das in diesem Kontext überhaupt Sinn macht.
-
Ja was denn nun? Willst du Vorzeichen oder nicht?
-
SeppJ schrieb:
Ja was denn nun? Willst du Vorzeichen oder nicht?
Das verstehe ich jetzt nicht. Dein Vorschlag war, aus "int" "unsigned int" zu machen. Das funktioniert aber nicht.
Das Programm sollte dann aus z.B. "b-764" 764 machen, tut es aber nicht.
-
Ok, dieses Feature war mir bisher gar nicht so bewusst. Dann eben so:
#include <iostream> #include <cctype> using namespace std; int main() { while (cin) if (isdigit(cin.peek())) { unsigned wert; cin >> wert; cout << wert << '\n'; } else cin.ignore(1); }Auch schön kurz und knackig.
P.S.: Oder noch einen Tacken kürzer:
int main() { do if (isdigit(cin.peek())) { unsigned wert; cin >> wert; cout << wert << '\n'; } while (cin.ignore(1)); }
-
SeppJ schrieb:
Ok, dieses Feature war mir bisher gar nicht so bewusst.
Das sieht eher aus wie ein Bug, nicht wie ein Feature. Denn auch die Ausgabe von negativen Zahlen funktioniert nicht, z.B. wird aus "b--764" "764".
SeppJ schrieb:
Dann eben so:
#include <iostream> #include <cctype> using namespace std; int main() { while (cin) if (isdigit(cin.peek())) { unsigned wert; cin >> wert; cout << wert << '\n'; } else cin.ignore(1); }Auch schön kurz und knackig.
P.S.: Oder noch einen Tacken kürzer:
int main() { do if (isdigit(cin.peek())) { unsigned wert; cin >> wert; cout << wert << '\n'; } while (cin.ignore(1)); }Jupp, das funktioniert beides. Aber wenn ich das richtig sehe, ist das doch geschummelt, da Du eine C-Bibliothek verwendest, oder?
-
redrew99 schrieb:
Das sieht eher aus wie ein Bug, nicht wie ein Feature. Denn auch die Ausgabe von negativen Zahlen funktioniert nicht, z.B. wird aus "b--764" "764".
Nein, das ist vom Standard so vorgesehen.
Jupp, das funktioniert beides. Aber wenn ich das richtig sehe, ist das doch geschummelt, da Du eine C-Bibliothek verwendest, oder?
Die C-Bibliothek ist Teil von C++. Aber meinetwegen:#include <iostream> #include <locale> using namespace std; int main() { locale loc; do if (isdigit(cin.peek(), loc)) { unsigned wert; cin >> wert; cout << wert << '\n'; } while (cin.ignore(1)); }Ist das jetzt besser?
-
redrew99 schrieb:
Was ich nicht verstehe ist, warum zusammenhängende Ziffern als Zahl gewertet werden.
Das liegt einfach daran, dass du nicht Zeichenweise einließt, sondern eine Sequence haben möchtest, in deinem Fall für einen Integer. Und wenn du einen Integer einlesen möchtest, dann ist der Einlesevorgang erst dann beendet, wenn man auf ein nicht-numerisches Zeichen stößt.
If you do not read character-wise, but extract an integer or a string, for example, you always read past the end of the input sequence. This is because the input operators read characters until they find a separator, or hit the end of the input sequence. Consequently, if the input contains the sequence ... 912749<eof> and an integer is extracted, the eofbit flag (but not failbit) is set.
Separator für Integer = ein nicht-numerisches Zeichen.
redrew99 schrieb:
Jupp, das funktioniert beides. Aber wenn ich das richtig sehe, ist das doch geschummelt, da Du eine C-Bibliothek verwendest, oder?
cctypeist in Ordnung, nicht in Ordnung wärectype.h
-
Gugelmoser schrieb:
Das liegt einfach daran, dass du nicht Zeichenweise einließt, sondern eine Sequence haben möchtest, in deinem Fall für einen Integer. Und wenn du einen Integer einlesen möchtest, dann ist der Einlesevorgang erst dann beendet, wenn man auf ein nicht-numerisches Zeichen stößt.
Ok.
Gugelmoser schrieb:
cctypeist in Ordnung, nicht in Ordnung wärectype.hOk. Hatte das schon oft gesehen hier, daß von der Verwendung von C-Bibliotheken abgeraten wird, sofern es irgend möglich ist. Aber egal.
-
SeppJ schrieb:
Nein, das ist vom Standard so vorgesehen.
Mag sein, die Funktion läßt sich zumindest nicht wirklich verwenden, selbst dann nicht, wenn man negative Zahlen extrahieren lassen möchte.
#include <iostream> #include <locale> using namespace std; int main() { locale loc; do if (isdigit(cin.peek(), loc)) { unsigned wert; cin >> wert; cout << wert << '\n'; } while (cin.ignore(1)); }SeppJ schrieb:
Ist das jetzt besser?
Sry, aber der Code funktioniert leider nicht.
Aber macht nichts, wir haben 2 funktionierende Versionen.
-
redrew99 schrieb:
Gugelmoser schrieb:
cctypeist in Ordnung, nicht in Ordnung wärectype.hOk. Hatte das schon oft gesehen hier, daß von der Verwendung von C-Bibliotheken abgeraten wird, sofern es irgend möglich ist. Aber egal.
Das ist richtig, nur hast du es falsch interpretiert: Header, die auf .h enden, sind für C. Für C++ gibt es eine Neuauflage für solche Header, die nicht auf
.henden, sondern mitcvorne anfangen. D.h.cctypeist richtig,ctype.hist falsch.
-
redrew99 schrieb:
Sry, aber der Code funktioniert leider nicht.
Aber macht nichts, wir haben 2 funktionierende Versionen.Sehr mitteilsam oder gar selbstständig bist du nicht gerade, oder?
if (isdigit(static_cast<char>(cin.peek()), loc))Und jetzt verstehst du auch vielleicht so langsam, wieso man nicht aus Prinzipientreue gegen schöne gute Standardfunktionen ist, bloß weil es sie in C auch gibt.
-
SeppJ schrieb:
Sehr mitteilsam oder gar selbstständig bist du nicht gerade, oder?
Berechtigte Frage. Schauen wir doch mal.
Nach Deinem PostSeppJ schrieb:
Im Moment sieht das nach einer unendlich umständlichen Art und Weise aus, (bis auf den Fehler) alle Zahlen aus einer Datei auszugeben.
(man beachte das "unendlich") habe ich mich hingesetzt und eine funktionierende Version gebastelt.
Sry, aber wer Kritik in der Form wie "unendlich umständlich" äußert, steht in der moralischen Pflicht, es besser zu machen. Interessanterweise gestaltete sich das
"besser machen" doch schwieriger als erwartet.Davon ab, vielen Dank für das Coaching und die Geduld, an Dich und natürlich an
Gugelmoser.
-
Hallo redrew99,
wenn ich das richtig verstanden habe, so geht es doch darum, alles zu überlesen, was keine Zahl ist und anschließend die Zahl zu lesen. Unter der Voraussetzung, dass keine isolierten '-' (und '+'?) Zeichen in der Datei stehen, sollten auch Vorzeichen erlaubt sein, und das ganze sollte von außen schaltbar sein.
Hier mal ein Manipulator, der direkt an der streambuf-Schnittstelle die Zeichen abgreift. In Summe ist das natürlich mehr Code, aber in der Anwendung wird's dann wieder schnuckelig einfach.#include <fstream> #include <iostream> #include <locale> template< typename E, typename Traits > std::basic_istream< E, Traits >& skip_until_number( std::basic_istream< E, Traits >& in ) { std::basic_istream< E, Traits >::sentry ok( in ); if( ok ) { std::ios_base::iostate state = std::ios_base::goodbit; try { const std::ctype< E >& ctype_ = std::use_facet< std::ctype< E > >( in.getloc() ); for( Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() ) { if( Traits::eq_int_type( m, Traits::eof() ) ) { state |= std::ios_base::eofbit; break; } const E c = Traits::to_char_type( m ); if( ctype_.is( std::ctype_base::digit, c ) || (in.flags() & std::ios_base::showbase && (c == E('+') || c == E('-'))) ) break; } } catch(...) { state |= std::ios_base::badbit; if( in.exceptions() & std::ios_base::badbit ) throw; } in.setstate( state ); } return in; } int main() { using namespace std; ifstream filestream("test.txt"); filestream >> showbase; // mit showbase ist Vorzeichen erlaubt, ohne nicht for( int wert; filestream >> skip_until_number >> wert; ) cout << wert << endl; cin.get(); return 0; }Das 'showbase'-Flag habe ich zweckentfremdet, um mit/ohne Vorzeichen schaltbar zu machen.
Gruß
Werner
-
Du hast echt nen... gewöhnungsbedürftigen Stil, Werner.

-
Werner Salomon schrieb:
Hallo redrew99,
wenn ich das richtig verstanden habe, so geht es doch darum, alles zu überlesen, was keine Zahl ist und anschließend die Zahl zu lesen. Unter der Voraussetzung, dass keine isolierten '-' (und '+'?) Zeichen in der Datei stehen, sollten auch Vorzeichen erlaubt sein, und das ganze sollte von außen schaltbar sein.Ja, genau. Wenn man schon so ein Programm schreibt, gehört meiner Ansicht nach ein "Schalter" für die Vorzeichen unbedingt mit rein, schließlich weiß man ja nie, ob man negative Zahlen braucht/nicht braucht.Vorstellbare Anwendungen für beides gibt es genug, z.B. Kontenstände(ja) oder Geburtsjahre(nein) auslesen.
Was ich überhaupt nicht verstehe ist, warum die Standardfunktion so gehalten ist, daß bei
#include <iostream> using namespace std; int main() { int wert; while (!(cin >> wert).eof()) if (cin) cout << wert << '\n'; else { cin.clear(); cin.ignore(1); } }einer Eingabe von z.B. "+-798" "798", aber bei einer Eingabe von "++-798" "-798" ausgegeben wird. Imho ergibt das keinen Sinn.
Werner Salomon schrieb:
Hier mal ein Manipulator, der direkt an der streambuf-Schnittstelle die Zeichen abgreift. In Summe ist das natürlich mehr Code, aber in der Anwendung wird's dann wieder schnuckelig einfach.[cpp]
Autsch. Ganz schöner Brocken.
Davon verstehe ich so gut wie nichts(wegen der Templates), dass muss ich mir erstmal in Ruhe anschauen.
Danke für den Code.
Bin dann erstmal off, muss morgen früh raus.