getline - string einlesen
-
Ethon schrieb:
Kann ich nicht reproduzieren.
Versuch mal eine Datei, deren letzte Zeile nicht auf einem Newline endet. Oder probier einen anderen Delimiter. Apropos, sollte dieser als Defaultwert ein Newline haben.
-
Stimmt, man könnte aber im Vorfeld prüfen, ob das letzte Zeichen ein Zeilenumbruch ist, falls nicht, fügt man halt eins ein.
Oder man prüft einfach nur, ob das Ende der Datei erreicht ist.
Falls ja, wird der String doch noch ausgegeben bzw. die Zeichen der letzten Zeile dort gespeichert.Bin dann off für heute.
-
kann man das eigtl eleganter implementieren? gefällt mir nicht so recht.
std::istream& getline(std::istream& in, std::string& out, char delim = '\n') { out.clear(); { char to_add; while(in.get(to_add)) { if(to_add == delim) return in; out.push_back(to_add); }; } return in; }
bb
-
Du hast denselben Bug wie Ethon. Ich denke, dass du beim ersten Erreichen von eof das Flag wieder zurücksetzen musst.
-
richtig - nachdenken 4tw -.-'
wollts eigtl noch testen, aber da hat mir dann doch iwie die lust gefehltstd::istream& getline(std::istream& in, std::string& out, char delim = '\n') { out.clear(); if(!in.eof()) { char to_add; while(in.get(to_add)) { if(to_add == delim) return in; out.push_back(to_add); }; in.setstate(in.rdstat() & ~std::ios::eof); } return in; }
-
Ethons Code funktioniert, auch wenn man am Ende einer Datei den Zeilenumbruch entfernt.
Allerdings verstehe ich nicht, wasfor(int c = in.get(); in; c = in.get())
da genau passiert. Mir ist klar, daß der Stream gelesen wird, aber nicht, wie.
Was bedeutetint c=in.get();
?
und müßte man nicht schreibenin.good()
statt
in
?
-
redrew99 schrieb:
Was bedeutet
int c=in.get();
? [...]in.get()
gibt ein Zeichen aus dem Stream zurück.redrew99 schrieb:
[...] und müßte man nicht schreiben
in.good()
stattin
?Nein, müsste man nicht. Das Prüfen auf
failbit
undbadbit
erledigt der "Convert-to-Pointer"-Operator (operator void *()
) ausios
.
-
SeppJ schrieb:
Ist das so eine Art Wettbewerb wie es immer schlechter geht?
Keine Ahnung. Aber wenn's so ist, dann darf ich wenigstens auch mitmachen
-
redrew99 schrieb:
Ethons Code funktioniert, auch wenn man am Ende einer Datei den Zeilenumbruch entfernt.
Das kann ich mir ehrlich gesagt nicht vorstellen. Wird dann auch die letzte Zeile verarbeitet bei folgendem Code?
string line; while(getline(in, line)) cout << line << endl;
-
Nope. Einerseits könnte man argumentieren dass eine Zeile ohne Zeilenende kein gültiges Token ist. Andererseits ist das in der Praxis Mist.
-
Also dieser Code (die Funktion ist von Ethan) funktioniert:
#include <iostream> #include <string> #include <fstream> using namespace std; std::istream& getline(std::istream& in, std::string& out, char delim) { out.clear(); for(int c = in.get(); in; c = in.get()) { if(c != delim) out += c; else break; } return in; } int main() { string s; ifstream filestream("test.txt"); for(;filestream.good();) { getline(filestream,s,'\n'); cout<<s<<endl; } return 0; }
-
Swordfish schrieb:
redrew99 schrieb:
Was bedeutet
int c=in.get();
? [...]in.get()
gibt ein Zeichen aus dem Stream zurück.Das verstehe ich, aber wie funktioniert das, daß ein Zeichen, also in der Regel keine Ziffer, einem Int zugewiesen wird?
Oder muß man die Funktion so verstehen, daß nicht ein Zeichen zurückgegeben wird, sondern die Position des Zeichens?
-
redrew99 schrieb:
Swordfish schrieb:
redrew99 schrieb:
Was bedeutet
int c=in.get();
? [...]in.get()
gibt ein Zeichen aus dem Stream zurück.Das verstehe ich, aber wie funktioniert das, daß ein Zeichen, also in der Regel keine Ziffer, einem Int zugewiesen wird?
Schon mal was von ASCII/ANSI-Code gehört? Und dass es überhaupt keinen Unterschied macht, ob man den in einem char oder einem int oder wasweißich speichert?
char ist insofern für Zeichen im ANSI-Code geeignet, da einerseits eine überladung des operator<< für ihn existiert, die seinen Numerischen Wert (z.B. 65) als ANSI-Code für das entsprechende Zeichen ('A') interpretiert und dieses dann in den Stream schreibt, andererseits, weil seine Größe dafür passt (1 Byte = 256 verschiedene "Codes" oder Zahlen => 256 Zeichen => ANSI).
-
redrew99 schrieb:
Also dieser Code (die Funktion ist von Ethan) funktioniert:
Kommt drauf an, was man unter "funktioniert" versteht. Denn das fail-Bit wird gesetzt, obwohl nur das eof-Bit gesetzt werden sollte. Wenn man wie ich bei fail- und bad-Bit Exceptions werfen lässt, fliegt einem das Programm um die Ohren, obwohl alles korrekt abgelaufen ist. Wenn man while(getline(...)) benutzt, fehlt die letzte Zeile, weil operator void*() nicht auf eof prüft.
Hacker: Das geht auch freundlicher.
-
Tut mir leid, passiert mir immer wieder
-
redrew99 schrieb:
Swordfish schrieb:
redrew99 schrieb:
Was bedeutet
int c=in.get();
? [...]in.get()
gibt ein Zeichen aus dem Stream zurück.Das verstehe ich, aber wie funktioniert das, daß ein Zeichen, also in der Regel keine Ziffer, einem Int zugewiesen wird?
In Wirklichkeit werden alle Werte sowieso als bits representiert.
get()
gibt einenint
zurück, damit ggf. auchEOF
zurückgegeben werden kann.redrew99 schrieb:
Oder muß man die Funktion so verstehen, daß nicht ein Zeichen zurückgegeben wird, sondern die Position des Zeichens?
Njet.
-
unskilled schrieb:
wollts eigtl noch testen, aber da hat mir dann doch iwie die lust gefehlt
dann liefere ich Dir dafür eine Testumgebung. Einfach in dem namespace test die eigene getline-Funktion einfügen, und das Programm übersetzen und ausführen:
#include <iostream> #include <string> #include <sstream> #include <streambuf> #include <cassert> #include <ctime> namespace test { // hier das getline einfügen } // .. oder obiges auskommentieren und folgende Zeile aktivieren, als Referenz sozusagen //namespace test = std; class BigBuf : public std::streambuf { static std::size_t const Len_of_a_line = 56; public: explicit BigBuf( int kbyte = 100 ) :m_i(0), m_n(kbyte*1000) { for( char* p = line; p != line+Len_of_a_line; ++p ) *p = '.'; line[Len_of_a_line-1] = '\n'; setg( line, line, line+Len_of_a_line ); } bool empty() const { return m_i >= m_n; } protected: int_type underflow() { if( (m_i += Len_of_a_line) >= m_n ) return traits_type::eof(); setg( line, line, line+Len_of_a_line ); return traits_type::to_int_type( *line ); } private: char line[Len_of_a_line]; std::size_t m_i, m_n; }; int do_main() { using std::istringstream; using std::cout; using std::endl; std::string s = "irgend etwas"; // -- getline testsuite { istringstream in("a b\nX"); test::getline( in, s ); assert( in.good() ); assert( s == "a b" ); // hier passt redrew99 Version 2 assert( in.get() == 'X' ); } { istringstream in("a b\n"); test::getline( in, s ); assert( in.good() ); assert( s == "a b" ); assert( in.get() == std::istream::traits_type::eof() ); } { istringstream in("a b"); test::getline( in, s ); // aus dieser Funktion kommt redrew99s Code Version 1 nie wieder heraus assert( !in.fail() ); // dieser Test wird weder von Ethon noch von unskilled passiert assert( in.eof() ); assert( s == "a b" ); } { istringstream in("x"); char c; in >> c; test::getline( in, s ); assert( in.fail() ); assert( in.eof() ); } { istringstream in("x"); in >> s; test::getline( in, s ); assert( in.fail() ); assert( in.eof() ); } { istringstream in("egal"); in.exceptions( std::ios_base::failbit ); test::getline( in, s ); // hier darf keine Exception geworfen werden } { // -- Performance Test (natürlich im Release-Mode auszuführen) std::clock_t const start = std::clock(); { BigBuf buf(10000); std::istream in(&buf); while( test::getline( in, s ) ) ; if( !buf.empty() ) std::cerr << "Lesefehler" << endl; } std::clock_t const duration = std::clock() - start; cout << "Dauer: " << double(duration)/CLOCKS_PER_SEC << "s" << endl; } cout << "Test Ende " << endl; std::cin.get(); return 0; } int main() { try { return do_main(); } catch( const std::exception& ex ) { std::cerr << "Exception: " << ex.what() << std::endl; } return -1; }
Gruß
Werner
-
Warum startest du in Zeile 73 nicht direkt mit einem leeren String?
-
Michael E. schrieb:
Denn das fail-Bit wird gesetzt, obwohl nur das eof-Bit gesetzt werden sollte.
Habe mal im I-net recherchiert. Demnach müssen beide Bits gesetzt werden, da
eofbit erst nach dem Versuch gesetzt wird, nach dem letzten Zeichen noch ein weiteres zu lesen. Da dieses dann nicht vorhanden ist, wird auch failbit gesetzt.Das Setzen des Failbits könnte man evtl. mit
in.clear(ios::goodbit);
korrigieren?
-
redrew99 schrieb:
Habe mal im I-net recherchiert. Demnach müssen beide Bits gesetzt werden, da
eofbit erst nach dem Versuch gesetzt wird, nach dem letzten Zeichen noch ein weiteres zu lesen. Da dieses dann nicht vorhanden ist, wird auch failbit gesetzt.C++98 §21.3.7.9.6-9 sagt, dass das Failbit außerhalb des istream::sentry-Hilfsobjekts genau dann gesetzt wird, wenn der Zielstring zu klein ist oder kein Zeichen extrahiert wurde. Dementsprechend stimmt deine Aussage nicht.