getline - string einlesen
-
Wenn man eine Textdatei einliest und auf der Konsole ausgibt, also z.B.:
ifstream filestream("test.txt"); for(string s;filestream.good();) { getline(filestream,s); cout<<s; }
wird anscheindend jedesmal der String s geleert bzw. gelöscht, da jede Zeile für sich, auch wenn sie kürzer als die vorhergehende ist, einwandfrei ausgegeben wird.
Wie funktioniert das?
-
redrew99 schrieb:
Wie funktioniert das?
Wie würdest du denn getline implementieren?
edit: Das ist nicht bloß als rhetorische Frage zu verstehen. Versuch es doch mal. Ist nicht so schwer, da eine simple, aber voll funktionsfähige, Version zu schreiben. Und dann siehst du auch, dass an dem Verhalten nichts geheimnisvolles ist.
-
SeppJ schrieb:
Wie würdest du denn getline implementieren?
so z.B.:
#include<iostream> #include<fstream> #include<string> using namespace std; int main() { ifstream filestream("test.txt"); //for (string s;!filestream.eof();) wäre wohl eine Alternative, soll aber nicht so gut sein. for(string s;filestream.good();) { getline(filestream,s); cout << s << endl; } //filestream.close(); return 0; }
-
redrew99 schrieb:
SeppJ schrieb:
Wie würdest du denn getline implementieren?
so z.B.:
#include<iostream> #include<fstream> #include<string> using namespace std; int main() { ifstream filestream("test.txt"); //for (string s;!filestream.eof();) wäre wohl eine Alternative, soll aber nicht so gut sein. for(string s;filestream.good();) { getline(filestream,s); cout << s << endl; } //filestream.close(); return 0; }
Implementieren != benutzen
Ich meine: Schreibe eine Funktion
std::ostream& my_getline(std::ostream &in, std::string &result)
, die eine Zeile ausin
liest, inresult
speichert und den Rest vonin
zurück gibt. Du wirstfeststellen, dass das komplette Ersetzen des Strings sehr einfach ist. Es wäre sogar im Gegenteil schwieriger, den ursprünglichen Inhalt teilweise zu überschreiben.
-
Da getline den Stream zurückgibt, der in einen bool konvertierbar ist, kann man getline einfach so verwenden:
for(string line; getline(file, line);) cout << line;
-
SeppJ schrieb:
Wie würdest du denn getline implementieren?
SeppJ schrieb:
Ich meine: Schreibe eine Funktion
std::ostream& my_getline(std::ostream &in, std::string &result)
, die eine Zeile ausin
liest, inresult
speichert und den Rest vonin
zurück gibt.Eine Funktion, die getline imitiert, würde ich so schreiben:
#include <iostream> #include <string> #include <fstream> using namespace std; void my_getline(istream &filestream,string &s) //Streamobjekt und String werden per Referenz übergeben. { s=""; //leert den (vorhandenen gefüllten) String; for (char ch;filestream.get(ch);) //Einzelnes Zeichen wird vom Stream in ch eingelesen. { if(ch!='\n') //Solange keinen Zeilenumbruch auftaucht, werden die einzelnen { //Zeichen zu einem String zusammengefügt. s+=ch; } else //if (ch=='\n') //Bei einem Zeilenumbruch verlasse die Schleife { break; } } } int main() { ifstream filestream("test.txt"); //Streamobjekt erstellen und Datei zum Lesen öffnen for(string s;filestream.good();) { my_getline(filestream,s); //Schleife zum Einlesen jeweils einer Zeile cout<<s<<endl; //Ausgabe der Zeile als String } return 0; }
Wie man einen Teilstream zurückgeben kann(wie du geschrieben hattest) da müßte ich mir nochmal den Kopf drüber zerbrechen, bin ich zumindest so nicht drauf gekommen.
Bin dann off für heute, g8@all
-
redrew99 schrieb:
Wie man einen Teilstream zurückgeben kann(wie du geschrieben hattest) da müßte ich mir nochmal den Kopf drüber zerbrechen, bin ich zumindest so nicht drauf gekommen.
Entweder verstehe ich hier gerade was grundsätzlich falsch oder ich bin total verwirrt. War deine Frage denn nicht, wieso sich getline eben so verhält und nicht anders?
-
Edit: Sorry, falsch gedacht.
-
Ich hatte mich nur gewundert, warum bei einer Schleife mit "getline(filestream, s)" nicht alle ausgelesenen Zeilen zusammen in "s" gespeichert werden, da ja vermutlich der Stream zeichenweise ausgelesen werden muß.
Also wenn eine Zeile zeichenweise ausgelesen und in den String übertragen wurde, ist der String ja nicht mehr leer, wenn man nun eine zweite Zeile ausliest und in den String überträgt, wird sie doch normalerweise hintenangehängt.Bei der Funktion, die ich geschrieben hatte, ist das Fall, wenn man nicht vor Beginn der Schleife in Zeile 9
den String leert.Die Funktion getline nachzuprogrammieren ist auf jeden Fall eine gute Sache, da man dann nicht nur Schablonen anwendet, sondern mehr Verständnis für die Klassen/Templates entwickelt.
-
Also, folgendes hab ich:
using std::istream; using std::string; istream& mgetline(istream& toread, string& tofill) { char array[500]; toread.read(array, 500); tofill = array; return toread; }
Werd ich gleich "verfeinern".
-
Hilfe?
-
So, erste Version a la Hacker:
istream& mgetline(istream&, string&, char = '\n', size_t = 500); istream& mgetline(istream& toread, string& tofill, char delim, size_t max) { char array[max]; toread.read(array, max); *(strchr(array, delim)) = 0; tofill = array; return toread; }
-
Ist das so eine Art Wettbewerb wie es immer schlechter geht? Da war ja die Simpelvorgabe von redrew99 noch besser. Die hat zumindest ohne Einschränkungen und noch dazu ohne Compilererweiterungen funktioniert.
-
redrew99 schrieb:
Also wenn eine Zeile zeichenweise ausgelesen und in den String übertragen wurde, ist der String ja nicht mehr leer, wenn man nun eine zweite Zeile ausliest und in den String überträgt, wird sie doch normalerweise hintenangehängt.
Wie kommst Du darauf?
Ich würde jetzt "logisch" annehmen, wenn man eine zweite Zeile ausliest und in den String überträgt, dass dann die zweite Zeile im String steht und nicht beide.
-
LordJaxom schrieb:
Wie kommst Du darauf?
Ich würde jetzt "logisch" annehmen, wenn man eine zweite Zeile ausliest und in den String überträgt, dass dann die zweite Zeile im String steht und nicht beide.
Naja, bei folgendem Programm ist das nicht so, wenn in Zeile 9 der String nicht geleert wird:
#include <iostream> #include <string> #include <fstream> using namespace std; void my_getline(istream &filestream,string &s) { //s=""; for (char ch;&filestream.get(ch);) { if(ch!='\n') { s+=ch; } else //if (ch=='\n') { break; } } } int main() { ifstream filestream("test.txt"); for(string s;filestream.good();) { my_getline(filestream,s); cout<<s<<endl; } return 0; }
-
SeppJ schrieb:
Ist das so eine Art Wettbewerb wie es immer schlechter geht? Da war ja die Simpelvorgabe von redrew99 noch besser. Die hat zumindest ohne Einschränkungen und noch dazu ohne Compilererweiterungen funktioniert.
Ja, du hast Recht - Schwachsinn. Merke jetzt auch, dass meine Funktion überhaupt nicht Funktioniert; auf Ideone hat sie das nähmlich (teilweise).
-
SeppJ schrieb:
Ich meine: Schreibe eine Funktion
std::ostream& my_getline(std::ostream &in, std::string &result)
, die eine Zeile ausin
liest, inresult
speichert und den Rest vonin
zurück gibt.Ich habe da noch eine Idee, man liest den Stream bis zum nächsten Zeilenumbruch aus und gibt dann einen Zeiger auf das nächste Zeichen zurück.
Was mir gerade einfällt, evtl. kann man das auch mit streamiteratoren umsetzen.
-
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; }
So isses korrekt nach Standard.
-
Nö, eof wird zu früh gesetzt, sodass bei einem while(getline(...)) die letzte Zeile nicht mehr verarbeitet wird.
-
Kann ich nicht reproduzieren.