Daten aus txt datei in Klasse einlesen
-
@Swordfish sagte in Daten aus txt datei in Klasse einlesen:
Sieh's mal so: Ich habe einen sstream pro Record anstatt der vorgeschlagenen 6 oder 7.
Der Vorschlag war 5 strings. Von 5 stringstreams war nie die Rede. Genaugenommen war überhaupt nie die Rede von irgendwelchen stringstreams.
Und überhaupt - bevor man das nicht vermessen hat ...
Ich dachte dass deine implizite Kritik sich gerade auf die schlechte Performance bezogen hat.
@hustbaer sagte in Daten aus txt datei in Klasse einlesen:
Geht natürlich nicht mit dem schicken operator >>.
Geht sicher. Aber viel Aufwand und wahrscheinlich nicht mehr hübsch.
Ich hab ja auch geschrieben geht nicht mit dem schicken operator >>. Natürlich kann man immer irgendeine Kranke Ausgeburt der Hölle bauen.
Sexy comes in all sizes though.
Nein. Ganz sicher nicht
-
@hustbaer sagte in Daten aus txt datei in Klasse einlesen:
Der Vorschlag war 5 strings. Von 5 stringstreams war nie die Rede.
Ich verdränge immer erfolgreich daß es auch andere Möglichkeiten gibt Zahlen aus strings zu kratzen
-
Ich kann dich verstehen.
Ich verdränge immer erfolgreich dass man blöd rumcasten muss wenn man nenchar
nachisdigit
& Co reinfüttern will.
(Ja, OK, ist ein anderes Thema, aber ich hab das wirklich schon vielfach erfolgreich verdrängt.)BTW: Ein Hoch auf from_chars. Endlich vernünftige Integer-/Float-Parser die man sich nicht selbst schreiben muss.
-
Etwas weniger 90ies style als Swordfish wäre meine Lösung (hier etwas vereinfacht, weil kein try/catch usw.) so ähnlich:
#include <fstream> #include <iostream> #include <string> #include <vector> using std::stoi; struct Person { unsigned int Nummer; std::string Name; unsigned int Geburtsjahr; unsigned int Eltern; unsigned int Kind; }; using Persons = std::vector<Person>; auto readFile() { Persons persons; std::ifstream in("Datei.txt"); if (!in.is_open()) { // error handling, maybe throw } std::string lines[5]; while (true) { for (auto &line : lines) { getline(in, line); } if (!in) { break; } persons.emplace_back( Person{static_cast<unsigned int>(stoi(lines[0])), lines[1], static_cast<unsigned int>(std::stoi(lines[2])), static_cast<unsigned int>(std::stoi(lines[3])), static_cast<unsigned int>(std::stoi(lines[4]))}); } return persons; } int main() { auto persons = readFile(); for (auto const &person : persons) { std::cout << person.Nummer << " : " << person.Name << " : " << person.Geburtsjahr << " : " << person.Eltern << " : " << person.Kind << "\n"; } }
PS: Ich finde cin furchtbar. Da richtige Fehlerbehandlung hinzubekommen ist die Hölle.
int i=0; cin >> i;
Tasächliche Eingabe: "Nö"
-
Danke für eure bisherigen Antworten!
Ich bin jetzt mit dem Ansatz von @hustbaer so weit gekommen, dass wenn ich eine Zahl eingebe, mir auch ein einzelner Datensatz (also 5 Zeilen) ausgegeben wird.
int main() { //Datei einlesen ifstream in("Datei.txt"); string Zeilen[5]; int i; cin >> i; cout << "\n"; while (true) { for (auto& i : Zeilen) getline(in, i); if (!in) break; // Es konnte keine Datei gefunden werden cout << setw(20) << "Nummer: " << Zeilen[0] << endl; //cout << setw(20) << "Name: " << Zeilen[1] << endl; cout << setw(20) << "Geburtsjahr: " << Zeilen[2] << endl; cout << setw(20) << "Eltern: " << Zeilen[3] << endl; cout << setw(20) << "Kinder: " << Zeilen[4] << endl; if (i = 5) break; //Ende der fünfzeiligen Ausgabe }
Das Programm reagiert so, dass der unterste fünfzeilige Eintrag die Null ist, dann wird hochgezählt, der oberste Eintrag hat also die höchste Zahl.
Das soll mir recht sein, ist ja nur wichtig, dass ich es weiß.
Jetzt will Ich einen Namen eingeben können und den zugehörigen Datensatz bekommen.Mache ich das mit:
string Datenbank = "Datei.txt"; string Name; cin >> Name; Datenbank.find(Name); Name = i;
oder bin ich da komplett auf dem Holzweg?
LG
-
Oder kann ich vielleicht sogar direkt den zweiten Eintrag des Vektors eingeben lassen, um den kompletten Vektor ausgeben zu lassen?
(Was wohl für die Benutzerfreundlichkeit nicht gerade gut wäre, weil die Eingabe, dann komplett fehlerfrei sein muss, aber vielleicht lässt sich das im nachhinein noch fixen)
-
Also zumindest mal ist dein
i
komisch.
Du hast nämlich 2i
s, einmal die Zahl, die du einliest, und einmal diez
-Variable von @hustbaer, die du offenbar umbenannt hast. Das verwirrt doch! Mach sowas nicht! (das z stand für zeile)Und das hier:
if (i = 5)
ist eine Zuweisung, kein Vergleich! Ich weiß nicht so recht, was du da erreichen willst. Ich habe keine Ahnung, was du mit "Das Programm reagiert so, dass der unterste fünfzeilige Eintrag die Null ist, dann wird hochgezählt, der oberste Eintrag hat also die höchste Zahl." meinst/sagen willst.Der Compiler kann bei solchen Dingen übrigens warnen. Schalte alle Warnungen ein und behebe dann die Warnungen!
Ich verstehe gerade nicht, was du mit dem i überhaupt erreichen willst. Du redest auch von vector-Einträgen, ich sehe aber gar keinen vector hier.
-
oh ja, danke, da ist einiges, was ich nicht brauch,
nur break reicht vollkommen.
(sonst wäre es eine endlosliste geworden )das eine i ist jetzt auch wieder ein z, auch wenn alles vorher ohne Fehlermeldung funktioniert hat.
Ich brauche ein i, da ich ja nicht alle Einträge ausgeben will, sondern nur einen.
Die Beispieldatei sähe so aus:
0001
Franz Müller
1996
"0004" "0005"
"0019" "0020"
0002
Helga Richter
1994
"0041" "0042"
"0019" "0020"
0003
Sabine Müller
1990
"0004" "0005"
"8" "9"
0004
Sandra Müller
1967
"10" "11"
"0001" "0003"
0005
Peter Müller
1966
"12" "13"
"0001" "0003"Wenn ich die 0 eingebe, dann gibt mir das Programm
0005
Peter Müller
1966
"12" "13"
"0001" "0003"Wenn ich die 1 eingebe, dann
Sandra Müller
1967
"10" "11"
"0001" "0003"
usw.Ich will aber Peter Müller eingeben und dann den Datensatz bekommen, der zu Peter Müller gehört.
-
Und mit Vector meinte ich
string Zeilen[5];
Sorry, falsch zugeordnet in meinem Kopf, die Grundfragestellung würde aber die gleiche bleiben
LG
-
Du mußt ersteinmal alle deine Personendaten in einem
std::vector<Person>
speichern (s. Code von @Swordfish und @Tyrdal).
Erst dann kannst du mittels einer Suchfunktion anhand eines Namens (oder anderen Attributen) dadrin suchen.
-
@PardiMau sagte in Daten aus txt datei in Klasse einlesen:
Ich habe eine Textdatei und will Daten in eine Klasse einlesen. Die Grobe Struktur wäre:
Nummer
Name
Nummer
Nummern
Nummern@PardiMau sagte in Daten aus txt datei in Klasse einlesen:
Die Beispieldatei sähe so aus:
Na wie jetzt? Wie ist ein Record genau aufgebaut?
Und müssen die Anführungszeichen wirklich sein? Das macht das ganze bloß unnötig komplifiziert.
-
@Swordfish Mit einer passenden Definition von
Nummern
stimmt das eh mit dem Beispiel überein
(Aber klar, wenn man mitNummern
meint dass da"1" "2" "42"
drin steht, dann sollte man das dazuschreiben.)
-
Sorry, da habt ihr recht. ich nehme die " " raus, dann wird´s wohl einfacher.
Leider muss ich ehrlich gesagt zugeben, dass ich durch die Codes nicht ganz durchblicke.
Ich habe auch nicht den Anspruch, dass alles möglichst schön und effizient ist. Gibt es denn irgendwie die Möglichkeit, auf meinem bestehenden Code aufzubauen und das eingelesene in eine Klasse zu packen oder einen Vector (wobei ich dachte, dass ein Vector nur aus Zahlen besteht, berichtigt mich bitte, wenn ich falsch liege)LG
-
@PardiMau
Der Einstiegswiderstand bei der STL ist relativ hoch, da Vieles auf abstrakten Konzepten beruht und als Einsteiger nicht intuitiv zu verstehen ist. Da muss man sich schon Mal ein Buch schnappen und etwas lesen. Sobald man aber Templates und Iteratoren halbwegs verstanden hat ergibt plötzlich alles Sinn.
Einstd::vector
ist ein Klassentemplate, da kann man fast alles reinstecken, nicht nur Zahlen. Man kann ihn auch problemlos in einer Funktion erzeugen und als Rückgabewert zurückgeben. Damit bietet sich das Einlesen in einer eigenen Funktion ja gerade an. Und nicht alles muss als Methode einer Klasse implementiert werden, gerade das Einlesen aus einer Datei würde ich in deinem Fall als freie Funktion implementieren.
Darfst du das Dateiformat frei wählen oder ist es vorgegeben?
-
@PardiMau sagte in Daten aus txt datei in Klasse einlesen:
Gibt es denn irgendwie die Möglichkeit, auf meinem bestehenden Code aufzubauen und das eingelesene in eine Klasse zu packen oder einen Vector
Sicherlich.
Als erstes bastelst du dir jetzt mal eine
struct Person
die die Daten aufnehmen soll.
Dann geht's ans Einlesen.Nimm diese Variante die du hattest:
while (true) { for (auto& i : Zeilen) getline(in, i); if (!in) break; // Es konnte keine Datei gefunden werden (sic) cout << setw(20) << "Nummer: " << Zeilen[0] << endl; //cout << setw(20) << "Name: " << Zeilen[1] << endl; cout << setw(20) << "Geburtsjahr: " << Zeilen[2] << endl; cout << setw(20) << "Eltern: " << Zeilen[3] << endl; cout << setw(20) << "Kinder: " << Zeilen[4] << endl; if (i = 5) // (sic) break; //Ende der fünfzeiligen Ausgabe (sic) }
An der Stelle
if (i = 5)
hast du jetzt die 5 Zeilen eines Eintrags inZeilen[0]
...Zeilen[4]
stehen.
Statt demif (i = 5)
machst du dort jetzt erstmal eine Variable vom TypPerson
hin und befüllst deren Felder.
Die "Listen" Felder (Eltern, Kinder) vergisst du erstmal, um die können wir uns später kümmern - immer schön der Reihe nacht.Zur Kontrolle ob das alles funktioniert hat baust du dir dann erstmal eine Ausgabe dazu - also einfach die
Person
Variable die du gerade befüllt hast ausgeben. Pack die Ausgabe am besten in eine eigene Unterfunktion, dann bleibt das übersichtlicher und die Funktion kannst du dann später auch einfach wiederverwenden.Dann nimmst du dir den Teil vor alles in einen
vector<Person>
zu packen. Das ist relativ easy, einfach vor der Schleife eine Variable mit Typvector<Person>
anlegen und in der Schleife die lokale Person Variable in den vector reinstopfen.Dann nimmst du die Ausgabe aus der Einleseschleife raus und machst nach der Einleseschleife eine Ausgabeschleife wo du bloss alles wieder ausgibst was du erst eingelesen hast.
Dann bist du schonmal ein gutes Stück weit gekommen.
Dann kannst du dir aussuchen was du als nächstes angehst: Suche einer bestimmten Person im vector oder erstmal das was wir auf die lange Bank geschoben hatten implementieren (Einlesen der Listen-Felder).
Dazu meldest du dich einfach nochmal hier.
Bzw. auch gerne wenn du bei einem der Schritte davor nicht weiterkommst.
-
-
@manni66 sagte in Daten aus txt datei in Klasse einlesen:
@hustbaer sagte in Daten aus txt datei in Klasse einlesen:
if (i = 5)
ist immer wahr.
if (i == 5)
?Copy Paste Fehler, das war sicherlich zur Überprüfung für PardiMau gedacht.
-
Freunde...
Das war der Code den er gepostet hatte. Mir ist schon klar dass das Quatsch ist. Ihm vermutlich auch, er wurde ja bereits darauf hingewiesen.
Nur da er die verbesserte Variante eben nicht gepostet hat, hab ich eben die alte zitiert.
Hätte es was geholfen wenn ich (sic) dazugeschrieben hätte?ps: Das Kommentar beim
break
danach ist auch Quatsch. Aber genau so wenig von mir.
ps2: Und das Kommentar beimbreak
davor auch. Und auch hier wieder: nicht von mir.
-
Okay, struct person habe ich gebastelt.
@hustbaer sagte in Daten aus txt datei in Klasse einlesen:
Statt dem if (i = 5) machst du dort jetzt erstmal eine Variable vom Typ Person hin und befüllst deren Felder.
was genau meinst du damit? Brauche ich dazu ein Array? Und wenn ich das dann ausgebe, was sollte dann optimalerweise da stehen?
LG
-
@PardiMau sagte in Daten aus txt datei in Klasse einlesen:
Okay, struct person habe ich gebastelt.
Und wie sieht die jetzt aus?
@DocShoe sagte in Daten aus txt datei in Klasse einlesen:
Darfst du das Dateiformat frei wählen oder ist es vorgegeben?
= ?
@PardiMau sagte in Daten aus txt datei in Klasse einlesen:
was genau meinst du damit? Brauche ich dazu ein Array?
Um eine Person zu lesen brauchst Du noch kein Array (oder
std::vector
).