[solved]Problem mit CSV-Dateien und zurückschreiben



  • Guten Morgen zusammen!

    Bei mir gehts um folgendes Problem:
    Ich hab eine CSV-Datei die ungefähr diese Struktur aufweist...

    AlbumInterpret;AlbumTitel;Gesamtzeit;AnzahlLieder;
    AlbumInterpret;TrackTitel;Tracknummer;Trackzeit;
    ...
    ...
    solange bis AnzahlLieder erreicht ist.

    Bsp:

    Arctic Monkeys;whatever people say thats what im not;123;3
    Arctic Monkeys;titel1;1;123
    Arctic Monkeys;titel2;2;123
    Arctic Monkeys;titel3;3;123

    Diese Werte möchte ich gerne zurücklesen und wieder in entsprechende Variablen speichern.
    Bis jetzt hab ich mit strtok() bis zum semikolon gesucht, klappt auch, allerdings sucht er immer wieder von vorne, und springt die werte nicht weiter.

    Das einzig größere Problem ist das lesen/zurückschreiben der Daten, den Rest würd ich hinkriegen, mir fehlt einfach nur ein Schubs in die richtige Richtung 😉

    Vielen Dank im Voraus

    Maguuu



  • Schubs: getline() liest eine komplette Textzeile ein - zerlegen kannst du sie dann mit find() und substr().



  • Vermutlich rufst Du strtok jedesmal gleich auf, du darfst strtok aber nur einmal mit dem String als erstem Parameter aufrufen, und dann solange mit NULL bis das Ende der Zeile erreicht ist. Dann liest er auch nicht immer wieder von vorne 😉

    Evtl. reicht Dir bei nem festen Format aber schon sscanf:

    sscanf( zeile, "%[^;];%[^;];%[^;];%[^;]", str1, str2, str3, str4 );
    

    EDIT:
    Hups, ich dachte doch für einen Moment glatt ich wäre im ANSI-C Forum 😮



  • Merci!
    getline() hatte ich auch schon geteste, allerdings wusste ich nicht wie ich das dann unterteilen kann, ich denke da ist substr() genau das richtige.
    Danke 😃

    Edit:
    soweit so gut, das vorgehen hab ich verstanden, allerdings kann ich mit find() ja, wenn ich nicht falsch liege, immer nur das erste, bzw die Position des ersten Semikolons bekommen oder?

    Edit2:
    Soweit so gut. Ich denke ich habs, aber ich glaube, dass man das ganze noch ne Menge kürzer gestalten könnte.

    #include <iostream>
    #include <string>
    using namespace std;
    int main()
    {
      string eingabe = "Arctic Monkeys;whatever people say thats what im not;123;3";
      string str1, str2, str3, str4;
      string substr1, substr2, substr3;
      short anz = 3;
      size_t pos1;
      size_t pos2;
      size_t pos3;
      size_t pos4;
    
      pos1 = eingabe.find(";");
      str1 = eingabe.substr (0,pos1);
      substr1 = eingabe.substr(pos1+1);
    
      pos2 = substr1.find(";");
      str2 = eingabe.substr(pos1+1,pos2);
      substr2 = substr1.substr(pos2+1);
    
      pos3 = substr2.find(";");
      str3 = eingabe.substr(pos2+1+pos1+1,pos3);
      substr3 = substr2.substr(pos3+1);
    
      pos4 = substr3.find(";");
      str4 = eingabe.substr(pos1+1+pos2+1+pos3+1,pos4);
    
    //Hilfsausgaben
      std::cout << "**********************************************" << std::endl;
      std::cout << "EingabeOrg: " << eingabe << std::endl;
      std::cout << "substring1: " << substr1 << std::endl;
      std::cout << "Substring2: " << substr2 << std::endl;
      std::cout << "Substring3: " << substr3 << std::endl;
      std::cout << "**********************************************" << std::endl;
      std::cout << "String1: " << str1 << std::endl;
      std::cout << "String2: " << str2 << std::endl;
      std::cout << "String3: " << str3 << std::endl;
      std::cout << "String4: " << str4 << std::endl;
      std::cout << "**********************************************" << std::endl;
    }
    


  • Maguuu schrieb:

    Soweit so gut. Ich denke ich habs, aber ich glaube, dass man das ganze noch ne Menge kürzer gestalten könnte.

    Ja, nicht nur kürzer, sondern man kann sich eine Menge Arbeit sparen, wenn man nicht zeilenweise liest, sondern gleich die Werte, wie sie später benötigt werden. Mach Dir dazu z.B. eine Klasse Album die wiederum Titel enthält und spendiere jeweils eine Einlese-Funktion.

    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream>
    
    template< char C >
    struct Char // Helferlein zum Lesen des ';' (s.u.)
    {
        friend std::istream& operator>>( std::istream& in, const Char )
        {
            char c;
            if( in >> c && c != C )
                in.setstate( std::ios_base::failbit );
            return in;
        }
    };
    
    class Titel
    {
    public:
        // -- Funktion zum Lesen eines Titels
        friend std::istream& operator>>( std::istream& in, Titel& titel )
        {
            Titel t;
            if( std::getline( in >> std::ws, t.m_interpret, ';' ) && std::getline( in, t.m_name, ';' )
                && in >> t.m_track >> Char<';'>() >> t.m_dauer )
            {
                titel = t;  // übernehmen, falls korekt gelesen
            }
            return in;
        }
    private:
        std::string m_interpret;
        std::string m_name;
        int m_track;
        int m_dauer;
    };
    
    class Album
    {
    public:
        // -- Funktion zum Lesen eines Albums
        friend std::istream& operator>>( std::istream& in, Album& album )
        {
            Album a;
            int nTitel;
            if( std::getline( in >> std::ws, a.m_interpret, ';' ) && std::getline( in, a.m_name, ';' )
                && in >> a.m_gesamtDauer >> Char<';'>() >> nTitel )
            {
                for( Titel titel; nTitel && in >> titel; --nTitel ) // Titel lesen
                    a.m_titel.push_back( titel );
                if( in )        // alles korrekt gelesen, dann übernehmen
                    album = a;  // ggf. durch swap ersetzen
            }
            return in;
        }
    private:
        std::string m_interpret;
        std::string m_name;
        int m_gesamtDauer;
        std::vector< Titel > m_titel; // die Titel in diesem Album
    };
    
    int main()
    {
        using namespace std;
        Album album;
        ifstream datei("input.csv");
        if( datei >> album )
        {
            cout << "Album gelesen " << endl;
        }
        return 0;
    }
    

    Gruß
    Werner



  • Maguuu schrieb:

    Edit:
    soweit so gut, das vorgehen hab ich verstanden, allerdings kann ich mit find() ja, wenn ich nicht falsch liege, immer nur das erste, bzw die Position des ersten Semikolons bekommen oder?

    Darum kannst du find() ja auch die Startposition angeben, ab der es suchen soll:

    size_t pos=-1;
    while((pos=line.find(";",pos+1))!=string::npos)
      ...
    

Log in to reply