Txt-Datei einlesen mit "Begrenzer" ->in seperate Variablen, mit STL
-
ich hab eine Txt-Datei:
bsp.John, Marschall; 110:10 Reginald, Bull; 112:11 Atlan, da Gonozal; 55:15 Perry, Rhodan; 123:11 Tako, Kakuta; 111:44jetzt muss ich die Datei auseinanderfriemeln und in eine Liste speichern..
nur wie bekomm ich die einzelnen Textsequenzen auseinanderhab bereits eine Class geschrieben:
class Personen { public: Personen::Personen( const string &first, const string &last, const string &pkt, const string &gpkt ) { setVorname(first); setNachname(last); setPunkte(pkt); setGegenPunkte(gpkt); } void setVorname( const string & first) { Vorname = first; } string getVorname() const { return Vorname; } void setNachname( const string & last) { Nachname = last; } string getNachname() const { return Nachname; } void setPunkte( const string & pkt) { punkte = pkt; } string getPunkte() const { return punkte; } void setGegenPunkte( const string & gpkt) { gegenpunkte = gpkt; } string getGegenPunkte() const { return gegenpunkte; } private: string Vorname; string Nachname; string punkte; //sollte int sein string gegenpunkte; //sollte auch int sein };und habe da eine möglichkeit die ich sehr unbefriedigend finde, da nur strings
auszug aus main...[cpp]int main() { std::list<Person*> myList; //weiss noch net ganz genau wie das ifstream infile("Daten.txt", ios::in); string vorn, nam; string pkt, gegenpkt; if(!infile) { cerr<<"File could not be opened"<<endl; exit(1); } while(infile) { getline(infile, nam, ','); getline(infile, vorn, ';'); getline(infile, pkt, ':'); getline(infile, gegenpkt, '\n'); // hier irgendwie in die Class abspeichern .. ..//und irgendwie in stl- liste gefriemelt -- mylist.push_front(Person); } return 0; }[/cpp]hatte mir auch schon sowas gedacht
while(infile>>name>>vorname>>punkte>>gegenpunkte)
nur das problem sind die begrenzer (, ; : und \n), compiler weiss ja net..was zu name und was zu vorname gehört.. usw brauch da wohl nee extra
"Auseinanderfriemel-funktion"
hoffe mein beispiel iss ausreichend beschrieben.hat jemand nee ahnung wie man das macht? mit stl und dem einlesen?
-
Normalerweise überlädt man die Operatoren für's Streaming. Ziemlich hilfreich bei der einfachen Verarbeitung von Strings sind die Boost String Algorithmen. Aber du wolltest ja nur STL, also hier ein Beispiel, dass nur STL nutzt:
#include <iostream> #include <fstream> #include <string> using namespace std; class Person { public: Person::Person(const string &first = "", const string &last = "", int pkt = 0, int gpkt = 0) { setVorname(first); setNachname(last); setPunkte(pkt); setGegenPunkte(gpkt); } void setVorname(const string & first) { Vorname = first; } string getVorname() const { return Vorname; } void setNachname(const string & last) { Nachname = last; } string getNachname() const { return Nachname; } void setPunkte(int pkt) { punkte = pkt; } int getPunkte() const { return punkte; } void setGegenPunkte(int gpkt) { gegenpunkte = gpkt; } int getGegenPunkte() const { return gegenpunkte; } private: string Vorname; string Nachname; int punkte; //ist jetzt int int gegenpunkte; //ist jetzt auch int //Dem Eingabestrom-Operator erlauben wir mal den Zugriff auf private Member, //dann kann direkt in ein Objekt gestreamt werden. friend istream &operator>>(istream &input, Person &p); }; istream &operator>>(istream &input, Person &p) { char zeichen; p.Vorname = ""; p.Nachname = ""; while(input.peek() != ',') { input.read(&zeichen, 1); p.Vorname += zeichen; } //Das Komma konsumieren input.read(&zeichen, 1); //Leerzeichen brauchen wir nicht! while(input.peek() == ' ') input.read(&zeichen, 1); while(input.peek() != ';') { input.read(&zeichen, 1); p.Nachname += zeichen; } //Das Semikolon konsumieren input.read(&zeichen, 1); //Leerzeichen brauchen wir nicht! while(input.peek() == ' ') input.read(&zeichen, 1); input >> p.punkte; //Den Doppelpunkt konsumieren input.read(&zeichen, 1); input >> p.gegenpunkte; //Das "Neue Zeile"-Zeichen konsumieren input.read(&zeichen, 1); return input; } ostream &operator<<(ostream &output, const Person &p) { output << "Vorname:\t" << p.getVorname() << "\n"; output << "Nachname:\t" << p.getNachname() << "\n"; output << "Punkte:\t\t" << p.getPunkte() << "\n"; return output << "GegenPunkte:\t" << p.getGegenPunkte() << "\n"; } int main() { Person p; ifstream test("test.txt"); while(!test.eof()) { test >> p; cout << p; } }Zeichenweise einlesen ist allerdings nicht sehr performant; besser wäre es die ganze Zeile zu lesen und diese mit boost::split zu zerschneiden. Die Punkte-Strings kann man dann zum Schluss mit boost::lexical_cast nach int konvertieren.
EDIT:
Beim operator<< fehlte das return.
-
Oh mein Gott, tonnenweise C++ Ramsch, wo eine Zeile fscanf genügt


-
so krass wie nillable hätt ichs auch nicht gemacht

Ich hätt es in etwa so gemacht:
- Ganze zeile einlesen (bis zum \n)
- Mit boost::tokenizer oder boost::split in teile splitten, die zeichen zum spliten wären dann eben ", ;:"
- jedes einzelne feld enstspricht dann einem wert.
- punkte udn gpkte mit atoi oder boost::lexcial_cast oder std::stringstream umwandeln.Aber da ohne boost... Schreib dir eine eigene splitfunkiont, die deine zeile bei ", " und und "; " und ":" splittet und als vector<string> zurück gibt.
-
proggingmania schrieb:
Oh mein Gott, tonnenweise C++ Ramsch, wo eine Zeile fscanf genügt


Jo! Wo sind nur die guten alten Zeiten hin? *träum*
@Maxi:
Kommst du jemals ohne Boost zurecht?
-
fscanfler schrieb:
proggingmania schrieb:
Oh mein Gott, tonnenweise C++ Ramsch, wo eine Zeile fscanf genügt


Jo! Wo sind nur die guten alten Zeiten hin? *träum*
Kannste ja immer noch benutzen; aber schön aufpassen, dass du Riesenbuffer nimmst, damit die Programmierung des Buffer-Overflows ein Easter Egg bleibt, gell

fscanfler schrieb:
@Maxi:
Kommst du jemals ohne Boost zurecht?Boost ist wunderbar! Mit boost::xpressive, könnte man den Eingabestrom-Operator zum Beispiel so lösen:
istream &operator>>(istream &input, Person &p) { mark_tag vorname(1), nachname(2), punkte(3), gpunkte(4); string zeile; sregex rxPerson = (vorname= -+(_w|_s)) >> ',' >> *_s >> (nachname= -+(_w|_s)) >> ';' >> *_s >> (punkte= +_d) >> *_s >> ':' >> *_s >> (gpunkte= +_d); smatch personenDaten; getline(input, zeile); if(regex_search(zeile, personenDaten, rxPerson)) { p.setVorname(personenDaten[vorname]); p.setNachname(personenDaten[nachname]); p.setPunkte(lexical_cast<int>(personenDaten[punkte])); p.setGegenPunkte(lexical_cast<int>(personenDaten[gpunkte])); } return input; }Klar, ist mit Kanonen auf Spatzen geschossen; hier würde auch split reichen, aber es soll nur ein kleines Beispiel sein, wie man sich mit Boost ausdrücken kann.
-
wegen fscanf... es ist ja auch ein c++-forum

@fscanfler: öhm... naja, früher schon. Jetzt hab ich boost echt lieb gewonnen. Sehe auch keinen Grund, warum man auf boost verzeichten sollte. Gibts welche? Ich benutz auch lieber boost::format als std::stringstream bzw. sprintf oder boost::assign und so. Macht alles leichter.
-
Maxi schrieb:
wegen fscanf... es ist ja auch ein c++-forum

@fscanfler: öhm... naja, früher schon. Jetzt hab ich boost echt lieb gewonnen. Sehe auch keinen Grund, warum man auf boost verzeichten sollte. Gibts welche? Ich benutz auch lieber boost::format als std::stringstream bzw. sprintf oder boost::assign und so. Macht alles leichter.
naja wenn das ziel bzw. vorgabe ist, möglichst kleine programme zu schreiben, kann man boost knicken, da zuviel unnützer kram mit reingeworfen wird. mehr als nur bei der STL selbst.
-
ein schlauer linker/compiler gibt nur das dazu, was gebraucht wird. Kann mir nciht vorstellen, dass boost::tokenizer oder so jetzt grad so fett sind.
-
Maxi schrieb:
ein schlauer linker/compiler gibt nur das dazu, was gebraucht wird. Kann mir nciht vorstellen, dass boost::tokenizer oder so jetzt grad so fett sind.
erzähl das mal dem aktuellen GCC.
-
ich sagte ein schlauer compiler/linker

Ne, kA warum der gcc so blöd ist und nicht checkt, dass er nicht alles linekn muss, was man ihm angibt. Und warum er nicht checkt, dass funktionen die die eine lib braucht vielleicht in einer in der kommandozeile folgenden lib drin sind. Naja, kA... komisch eben.