CSV-Datei mit unterschiedlich vielen Einträgen richtig einlesen



  • Hallo liebe C++ Community,

    ich habe 2 kleine Problemchen auf dem weg zu einer von Studentenhand erstellten kleinen Datenbank. Dabei geht es um das nutzen von replace_if und von dem einlesen der richtigen Zeile

    Die Datenbank(csv) sieht ungefähr folgendermaßen aus:

    ID-1, ID-2, ID-3, ID-4, Gleichungen, Id-5, Werte
    1, 1, 1, 1, K_1 =a | K_2 =x, 2, 12.2 | 2.4
    2, 1, 2, 3, K_1 =b | K_2 =c |K_3=x, 2, 2.7 | 0.3 | 4
    3, 2 1 2, K_1=d 4, 2

    also es gibt 7 Spalten, wobei in Spalte 5 und 7 mehrere Werte durch | getrennt stehen.
    Ziel: ich gebe eine ID-1 ein und erhalte eine ID-4 und die Konstanten K_1, K_2 und K_3 falls vorhanden.

    Ansatz:
    getline Befehl, und erhalten von einem string für jede Zeile, anschließend Umwandlung in einen stringstream für die interessanten Dateien und anschließend trennung der spalte 7 an den | und konvertieren in integer(Zeile4)/double(Zeile7) je nachdem.

    Problem:
    ich schaffe es noch nicht, die richtige Zeile auszusuchen in der bei ID-1 z.B. die 2 steht.
    Hier ein ähnliches Problem aber aus der Lösung wurde ich nicht schlau:

    https://www.c-plusplus.net/forum/topic/319437/csv-datei-nach-bestimmten-begriff-durchsuchen-und-zeile-in-der-der-string-vorkommt-in-array-speichern/14

    2: Ich will ja die Spalte 7 aufteilen in K_1bis K_n Konstanten, aber diese sind durch | getrennt, der >> Befehl geht a meine ich von durch Leerzeichen getrennte Werte aus, ginge das mit replace_if oder einem anderen ähnlich simplen Befehl?
    Ich habe es mit dem for Ansatz probiert von minute 9:30 aus folgendem Video
    https://www.youtube.com/watch?v=rnGoCWNtNR0

    aber irgendwie bekam ich vom Programm (Visual Studio) einen Fehler angezeigt, dass er dann den ursprünglichen stringstream nicht mehr findet...

    Hier der vorläufige Code :

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <algorithm> //um replaceif zu nutzen

    using namespace std;

    int main()
    {
    int ID_1;

    ifstream datei("Pfad");
    if (!datei.is_open()) std::cout << "Error: File Open" << '\n';
    
    string ID_1string;
    string ID_2string;
    string ID_3string;
    string ID_4string;
    string Gleichungenstring;
    string ID_5ring;
    string Konstantenstring;
    
    while (datei.good) //Hier fehlt garantiert die Auswahl der richtigen Zeile wobei ID_1 dem wert der zuvordefinierten ID_1 entsprechen soll
    
    	getline(fittings, ID_1string, ',');
    	getline(fittings, ID_2string, ',');
    	getline(fittings, ID_3string, ',');
    	getline(fittings, ID_4string, ',');
    	getline(fittings, Gleichungenstring, ',');
    	getline(fittings, ID_5string, ',');
    	getline(fittings, Konstantenstring, ',');
    
    	//nun folgt das Konvertieren der später benötigten Werte aus String zunächst in stringstream und dann in das eigentliche Dateiformat, vlt gibt es ja noch schöneren Weg, aber hauptsache es klappt
    	stringstream PFSS(ID_4string);
    	int ID_4;
    	PFSS >> ID_4;
    
    	int n = count(Konstantenstring.begin(), Konstantenstring.end(), '|'); //Da verschieden viele Konstanten in "Konstanten" stehen können hier die Fallunterscheidung, ich nehme an mehr als 8 werden es nicht werden
    	
    	replace_if(Konstantenstring.begin(), Konstantenstring.end(), Konstantenstring[i]='|', ' ');  //Das funktioniert so noch nicht, jemand eine Idee wie ich alle '|' durch Leerzeichen ersetzen kann um den stringstream dann zu Konstanten werden zu lassen?
    	
    	
    	stringstream fpSS(fpstring);
    
    	
    
    
    	switch (n)
    	{
    		case 1:
    			double K_1;
    				fpSS >> K_1;
    				break;
    
    		case 2:
    			double K_1;
    			double K_2;
    			fpSS >> K_1 >>K_2;
    			break;
    
    		case 3:
    			double K_1;
    			double K_2;
    			double K_3;
    			fpSS >> K_1 >> K_2 >>K_3;
    
    			break;
    
    		case 4:
    			double K_1;
    			double K_2;
    			double K_3;
    			double K_4;
    			fpSS >> K_1 >> K_2 >> K_3 >>K_4;
    
    
    		case 5:
    			double K_1;
    			double K_2;
    			double K_3;
    			double K_4;
    			double K_5;
    			fpSS >> K_1 >> K_2 >> K_3 >> K_4 >>K_5;
    
    			break;
    

    //usw bis 8
    }
    }

    Wäre für jede Hilfe echt sehr dankbar 🙂

    Liebe Grüße



  • Zeile 32 : statt fpstring sollte da eig Konstantenstring stehen, dachte nur durch all die selbstgewählten Abkürzungen steigt keiner durch...



  • @Sonnentag sagte in CSV-Datei mit unterschiedlich vielen Einträgen richtig einlesen:

    aber irgendwie bekam ich vom Programm (Visual Studio) einen Fehler angezeigt, dass er dann den ursprünglichen stringstream nicht mehr findet...

    Copy&Paste



  • Und hör auf in alten Threads rumzuspammen


  • Mod

    Boah, geht's noch? Erst einmal 5 Stunden Notfall-Bann, bevor hier noch mehr Nekromantie betrieben wird. In der Zeit bitte über Netiquette nachdenken und wie man bei anderen rüber kommt, wenn man alte Threads mit belanglosen Verweisen auf die eigenen Fragen vollspammt.



  • Wäre es nicht besser, du würdest zuerst die ganze CSV-Datei in eine passende Datenstruktur einlesen (so groß wird diese doch nicht sein, oder?) und dann dadrin suchen?
    vector<vector<string>> wäre hier für den Anfang wohl die einfachste Datenstruktur dafür (Liste von Zeilen mit jeweils Liste von Spalten).

    Und die Einträge mit | kannst du dann ebenfalls mittels getline(..., '|') auslesen, wenn du den string als Parameter für istringstreambenutzt (dafür dann am besten eine eigene Datenstruktur anlegen und die Werte passend setzen):

    vector<string> konstanten;
    istringstream is(Konstantenstring);
    
    while (is)
    {
      string konstante;
      if (getline(is, konstante, '|'))
        konstanten.push_back(konstante);
    }
    

    (die Header mußt du entsprechend einbinden und auf std:: habe ich hier jetzt auch mal verzichtet. Und eigentlich verwende ich englische Variablennamen ;-).



  • @Th69 sagte in CSV-Datei mit unterschiedlich vielen Einträgen richtig einlesen:

    vector<vector<string>>

    std::unordered_map<int, dataset> ...

    dataset wo wir doch schon von richtigen(tm) Datentypen reden.

    Ich fang' mal an, der nächste ambitionierte kann ja weitermachen.

    #include <array>
    #include <vector>
    #include <string>
    #include <unordered_map>
    #include <iostream>
    
    class dataset
    {
    	std::array<int, 5> ID;
    	std::vector<std::string> Gleichungen;
    	std::vector<int> Werte;
    
    	friend
    	std::istream& operator<<(std::istream &is, dataset &ds)
    	{
    		// lies die ersten 4 id's und check daß das zeichen dazwischen ',' ist.
    		// lies mit getline bis zum nächsten ',' und stopf es in einen stringstream
    		// lies von diesem stringstream mit getline bis zum nächsten '|' und stopf es in Gleichungen
    		// lies ID[4]
    		// lies mit getline den rest der zeile aus is
    		// stopf das in einen stringstream und extrahiere ints daraus und checke das entweder eof oder das zeichen dazwischen '|' ist.
    		// stopf die ints in Werte.
    		return is;
    	}
    };
    
    class data
    {
    	std::unordered_map<int, dataset> foo;
    
    	friend
    	std::istream& operator<<(std::istream &is; data &d)
    	{
    		// lies dataset s aus is bis eof oder der stream tot ist.
    		// plan b: baue einen c-tor fuer dataset der iteratoren nimmt und gib ihm 
    		// std::istream_iterator<dataset>{whatever_stream}, std::istream_iterator<dataset>{}
    		return is;
    	}
    };
    

    @Sonnentag Falls Du es noch nicht mitbekommen haben solltest, so wie in Deinem Eingangspost macht man soetwas in C++ nicht.



  • @Swordfish sagte in CSV-Datei mit unterschiedlich vielen Einträgen richtig einlesen:

    @Th69 sagte in CSV-Datei mit unterschiedlich vielen Einträgen richtig einlesen:

    vector<vector<string>>

    std::unordered_map<int, dataset> ...
    dataset wo wir doch schon von richtigen(tm) Datentypen reden.

    Ich schrieb ja auch "für den Anfang wohl die einfachste Datenstruktur". Ich glaube nicht, daß ein Anfänger etwas mit std::unordered_mapanfangen kann (ich selber sehe hier aber auch keinen Vorteil).