csv Datei nach bestimmten Begriff durchsuchen und Zeile in der der String vorkommt in Array speichern



  • Hallo!

    Ich versuche gerade ein .csv Datei mit meinem c++ Programm aus zu lesen und diese dann später zeilenweise in einem Array zu speichern. Also ein Zeile besteht aus 4 spalten und soll dem nach ein Array von 0-3 füllen.
    So aber jetzt mein Problem ich bekomme es gar nicht richtig hin die Datei einzulesen.
    Hier ist mein Code den ich im Netz gefunden hab nach dem ich den halben Nachmittag gegoogelt hab, hat jemand einen Tipp was ich falsch mache?
    hier der Code:

    fstream datei1("testdatei.csv", ios::in);
    
        string s;
        datei1.open("testdatei.csv", ios::in); // Öffne Datei aus Parameter
        while (!datei1.eof())          // Solange noch Daten vorliegen
        {
            getline(datei1, s);        // Lese eine Zeile
            cout << s << endl;    // Zeige sie auf dem Bildschirm
    
        }
        datei1.close();
    

    Wäre super wenn mir jemand helfen könnte, damit ich mir endlich überlegen kann wie ich das mit dem Durchsuchen und Array anstellen kann.
    lg
    LiinaLii



  • Hier ist mein Code den ich im Netz gefunden hab nach dem ich den halben Nachmittag gegoogelt hab, hat jemand einen Tipp was ich falsch mache?

    Ja, das steht alles im ersten Satzteil: Code zusammengegoogelt. 🙂 Gar nicht rühmlich.

    fstream datei1("testdatei.csv", ios::in); // Nimm gleich ifstream.
    
        string s;
        datei1.open("testdatei.csv", ios::in); // Könnte gleich im Konstruktor erledigt werden.
        while (!datei1.eof()) // Autsch, ganz schlecht. So eine Weiterlaufbedingung ist verpönt und sollte in diesem Fall direkt durch das getline ersetzt werden.
        {
            getline(datei1, s);
            cout << s << endl;
    
        }
        datei1.close(); // überflüssig
    

    Was du hier tust, ist doch einfach den kompletten Inhalt der Datei auszugeben.
    Das geht auch mit

    std::ifstream stream("testdatei.csv");
    std::copy( std::istreambuf_iterator<char>{stream}, std::istreambuf_iterator<char>{}, std::ostreambuf_iterator<char>{std::cout} );
    

    (Ungetestet)
    Was du aber natürlich willst, ist diese Schleife so umbauen, dass du die einzelnen in der Datei enthaltenen Zahlen in ein Array einlesen kannst.
    Aber -

    Wäre super wenn mir jemand helfen könnte, damit ich mir endlich überlegen kann wie ich das mit dem Durchsuchen und Array anstellen kann.

    Dir fehlen viele Grundlagen. Ich könnte dir ein Programm vorlegen, dass genau das tut - aber lernen tust du so nichts.
    Hier findest du Tipps wie du ein gutes Grundlagenbuch findest.



  • Hallo LiinaLii,

    ist wohl ein wenig Sommerloch, sonst hättest Du bestimmt schon mehr Antworten bekommen.

    LiinaLii schrieb:

    Hier ist mein Code den ich im Netz gefunden hab nach dem ich den halben Nachmittag gegoogelt hab, hat jemand einen Tipp was ich falsch mache

    So ca. 98% von dem was im Internet steht ist Mist. Die Kunst besteht darin, die 2% zu finden 😉

    Du fragst was Du falsch machst. Unabhängig von dem, was Sone schon geschrieben hat, ist wahrscheinlich schon der Ansatz mit dem Array zumindest suboptimal. Schreibe mal, was mit den Daten geschehen soll, nachdem(!) sie im Array eingelesen wurden, dann kann man das besser beurteilen. Um welchen Typ Daten handelt es sich (double, int, string,..)?

    Ein Lösung, die zum überwiegenden Teil auf solche Art Anfragen passt, wie Du sie hier gestellt hast, sieht so aus, dass Du eine Struktur (oder Klasse) baust. Diese Struktur sollte den Anforderungen genügen, die Du nach(!) dem Einlesen an die Struktur stellst.
    Ansonsten gilt: Lese das ein, was Du auch später im Programm verarbeiten willst; also keine Zeilen, denn Zeilen brauchst Du nicht!
    Und dann schreibe man eine kleine Funktion die eine Instanz dieser Struktur von einem std::istream liest.

    Mal angenommen, es sind vier Integer-Werte ...

    struct EineStruct
    {
        int i1_, i2_, i3_, i4_;
    };
    

    Weiter angenommen in der Datei stehen sie einfach mit Tabulator oder Leerzeichen getrennt hintereinander ..

    // Lesefunktion für eine Instanz von 'EineStruct'
    std::istream& operator>>( std::istream& in, EineStruct& s )
    {
        return in >> s.i1_ >> s.i2_ >> s.i3_ >> s.i4_;
    }
    

    .. und im Hauptprogramm:

    ifstream datei1("testdatei.csv");
        if( !datei1.is_open() )
        {
            cerr << "Fehler beim Oeffnen" << endl;
        }
        else
        {
            EineStruct s;
            while( datei1 >> s ) // bricht ab, bei Fehler (bzw. Fehler wg. EOF)
            {
                // hier kannst Du sicher sein, dass 's' korrekt gelesen wurde
                // mache was mit 's'
                cout << "i2 = " << s.i2_ << endl;
            }
        }
    

    Gruß
    Werner



  • Hallo!
    Danke erstmal für eure Tipps! Also es handelt sich um 5 Strings die in einer Zeile stehen, es soll ja ein Büchereiprogramm werden. Also steht in den Strings Author, Genre, Erscheinungsjahr, Titel und eine kurzbeschreibung. Nun will ich das wenn man in meiner Winform in einer Textbox nach einem der Strings sucht die Zeile mit dem gesuchten Inhalt ausgegeben wird. Z.B. jemand sucht Author X dann öffnet sich ein Fenster mit den Büchern von Author X (die zuvor aus meiner .cvs datei gesucht wurden) Dafür hatte ich gedacht ich suche nach den Ensprechenden Zeilen in den der Author vorkommt, speicher sie in einem Array und gebe das Array über mehrer Textboxen, die Sortiert sind nach Author, Titel etc wieder in einer neuen WinForm aus.



  • Hallo LiinaLii,

    wie sind die Strings von einander getrennt? Möchtest Du auch nach was anderen als den Namen des Autor suchen?
    poste doch einfach mal einige Zeilen als Beispiel ...



  • Hallo Werner!

    Ich hab die csv Datei so angelegt

    Author ;Title;Genre;Erscheinungsjahr;Zusammfassung;Bewertung
    Brian Keene ;Eine Versammlung von Kr„hen;Horror;2013;Brinkley Springs ist eine ruhige, kleine Stadt. Einige sagen, die Stadt liege im Sterben ...
    

    aber ich hab halt Probleme wie ich jetzt nach den Inhalten suchen könnte, ich möchte später nach Author, Titel und Genre suchen können (Wenn ein Begriff in mehreren Zeilen vorkommt sollten die entsprechenden Zeilen ausgegeben werden.
    Evtl. ist auch mein Ansatz mit der cvs Datei nicht der beste aber mir wird einfach nicht klar wie ich es besser machen könnte oder wie es einfacher bzw. besser wäre.



  • Eine Möglichkeit sieht so aus:

    struct Book
    {
        std::string author, 
                    title,
                    genre;
    
        unsigned yearOfPublishing;
    
        std::string summary, 
                    rating;
    };
    

    Anschließend liest du alle Strings mit std::getline und ';' als Delimiter ein (und yearOfPublishing ganz normal und überspringst dann ein Zeichen mit ignore()).
    Dann trimmst du die Strings ('schneidest' alle Leerzeichen vorne und hinten ab).

    Du könntest auch eine Enumeration nutzen, um das Genre zu speichern.



  • LiinaLii schrieb:

    aber ich hab halt Probleme wie ich jetzt nach den Inhalten suchen könnte, ich möchte später nach Author, Titel und Genre suchen können (Wenn ein Begriff in mehreren Zeilen vorkommt sollten die entsprechenden Zeilen ausgegeben werden.
    Evtl. ist auch mein Ansatz mit der cvs Datei nicht der beste aber mir wird einfach nicht klar wie ich es besser machen könnte oder wie es einfacher bzw. besser wäre.

    Hi,
    mir war eben langweilig und hab da mal was gebastelt. Du kannst einfach mal copy&paste machen, die test.csv Datei wie im Quellcode beschrieben erstellen, und das Programm ausführen. Was hälst du davon?

    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <map>
    #include <string>
    #include <vector>
    using namespace std;
    
    enum   kategorien { author, genre, erscheinungsjahr, titel, kurzbeschreibung };
    struct buch
    {
    	string author;
    	string genre;
    	string erscheinungsjahr;
    	string titel;
    	string kurzbeschreibung;
    };
    
    typedef const string* value_type_key;
    typedef const buch*   value_type_value;
    
    typedef kategorien key_type;
    typedef map<value_type_key,value_type_value> value_type;
    
    typedef map<key_type,value_type> datenbank;
    
    istream& operator>>( istream& in, buch& b ) // Ein Buch einlesen
    {
    	const char SEP = ';';
    	getline( in, b.author, SEP );
    	getline( in, b.genre, SEP );
    	getline( in, b.erscheinungsjahr, SEP );
    	getline( in, b.titel, SEP );
    	getline( in, b.kurzbeschreibung );
    	return in;
    }
    
    ostream& operator<<( ostream& out, const buch& b ) // Ein Buch einlesen
    {
    	return
    		out << b.author << " | " << b.genre << " | " << b.erscheinungsjahr << " | " << b.titel << " | " << b.kurzbeschreibung;
    }
    
    istream& skip_line( istream& in ) // Eine Zeile verwerfen
    {
        return in.ignore(numeric_limits<streamsize>::max(),'\n');
    }
    
    void alle_buecher_einlesen( const string& dateiname, vector<buch>& buecher ) // Liest alle Bücher von der csv-Datei ein.
    {
    	ifstream file( dateiname.c_str() );
    	file >> skip_line; // Spaltenüberschriften brauchen wir ja nicht.
    	for(buch b; file>>b; buecher.push_back(b)); // Alle Buecher einlesen und abspeichern.
    }
    
    void datenbank_erstellen( const vector<buch>& buecher, datenbank& db )
    {
    	for(auto it=begin(buecher); it!=end(buecher); ++it)
    	{
    		db[author          ][&it->author          ] = &*it;
    		db[genre           ][&it->genre           ] = &*it;
    		db[erscheinungsjahr][&it->erscheinungsjahr] = &*it;
    		db[titel           ][&it->titel           ] = &*it;
    		db[kurzbeschreibung][&it->kurzbeschreibung] = &*it;
    	}
    }
    
    void buecher_suchen( key_type kat, const string& suchtext, const datenbank& db )
    {
    	const value_type& value = ( *(db.find(kat)) ).second;
    
    	for(value_type::const_iterator it=begin(value); it!=end(value); ++it)
    	{
    		const string& key = *(it->first);
    
    		if( key.find(suchtext) != std::string::npos )
    		{
    			const buch& b = *(it->second);
    			cout << b << '\n';
    		}
    	}
    	cout << '\n';
    }
    
    int main()
    {
    	/*
    		test.csv:
    			Author;Genre;Erscheinungsjahr;Titel;Kurzbeschreibung
    			Hans Wurst;Drama;04.05.1987;Hans Wursts Buch; Ein altes Buch
    			Max Mustermann;Krimi;07.07.2013;Max Mustermanns Buch; Ein neues Buch
    			Hans Wurst;Drama;04.05.1987;Hans Wursts Buch; Noch ein altes Buch
    			Max Mustermann;Krimi;07.07.2013;Max Mustermanns Buch; Noch ein neues Buch
    	*/
    
    	const string dateiname = "test.csv";
    	vector<buch> buecher;
    	alle_buecher_einlesen( dateiname, buecher );
    
    	datenbank db;
    	datenbank_erstellen( buecher, db );
    
    	buecher_suchen( author, "Wurst", db );
    	buecher_suchen( genre, "Krimi", db );
    	buecher_suchen( erscheinungsjahr, "1987", db );
    	buecher_suchen( titel, "Buch", db );
    	buecher_suchen( kurzbeschreibung, "neues", db );
    }
    


  • Sone, wie hättest du das ganze gelöst? Irgendwie find ich meine Lösung nicht so optimal.



  • So hätte ich die Basis gelöst:

    #include <iostream>
    #include <string>
    #include <boost/algorithm/string/trim.hpp>
    
    template<char Ch>
    struct CVSParser
    {
    	static char constexpr delimiter = Ch;
    
    	static std::istream& delim(std::istream& is)
    	{
    		if( is.get() != Ch )
    			is.setstate( std::ios_base::failbit );
    
    		return is;
    	}
    
    private:
    	std::istream* mStream;
    
    public:
    
    	CVSParser( std::istream& is ):
    		mStream{&is} {}
    
    	template<typename T>
    	CVSParser& operator>>( T& rval )
    	{
    		(*mStream) >> rval >> delim;
    		return *this;
    	}
    
    	// Weitere Spezialisierungen für Strings zu ergänzen
    	CVSParser& operator>>( std::string& rval )
    	{
    		std::getline(*mStream, rval, delimiter);
    		boost::trim(rval);
    		return *this;
    
    	}
    };
    
    /// //////////////////////////////////////////////////////////////////////////////////////
    
    struct Book
    {
        std::string author,
                    title,
                    genre,
                    summary,
                    rating;
    
        unsigned yearOfPublishing;
    };
    
    std::istream& operator>>( std::istream& is, Book& b )
    {
    	CVSParser<';'> parser{is};
    
    	parser >> b.author >> b.genre >> b.yearOfPublishing >> b.title >> b.summary >> b.rating;
    
        return is;
    }
    
    std::ostream& dump( std::ostream& os, Book const& b )
    {
    	return os << "Autor: " << b.author << '\n'
    	          << "Titel: " << b.title << '\n'
    	          << "Genre: " << b.genre << '\n'
    	          << "Erscheinungsjahr: " << b.yearOfPublishing << '\n'
    	          << "Zusammenfassung: " << b.summary << '\n'
    	          << "Bewertung: " << b.rating;
    }
    
    #include <sstream>
    
    int main()
    {
    	std::istringstream stream
    	{  "Hans Wurst;Drama;1987;Hans Wursts Buch; Ein altes Buch; Eine supi Bewertung"  };
    
    	Book b;
    	stream >> b;
    	dump(std::cout, b);
    }
    

    Was die Datenbank angeht, hätte ich wohl zu einer Enumeration tendiert, und dann einfach per switch ein Prädikat für std::find_if festgelegt.



  • Sone schrieb:

    Was die Datenbank angeht, hätte ich wohl zu einer Enumeration tendiert, und dann einfach per switch ein Prädikat für std::find_if festgelegt.

    Wieso nicht mit einem abstrakten Funktor, der je nach Auswahl überladen ist?



  • Skym0sh0 schrieb:

    Wieso nicht mit einem abstrakten Funktor, der je nach Auswahl überladen ist?

    Auswahl? Die Kategorie soll zur Laufzeit feststehen können. Oder was meinst du mit "Auswahl"?



  • Hallo LiinaLii,

    LiinaLii schrieb:

    Ich hab die csv Datei so angelegt

    Author ;Title;Genre;Erscheinungsjahr;Zusammfassung;Bewertung
    Brian Keene ;Eine Versammlung von Kr„hen;Horror;2013;Brinkley Springs ist eine ruhige, kleine Stadt. Einige sagen, die Stadt liege im Sterben ...
    

    Was ist mit der Bewertung? steht hinter der Zusammenfassung noch ein ';'? Steht die erste Zeile so wie oben mit in der Datei?
    .. einige Details sind noch zu klären.
    Ansonsten - aller guten Dinge sind drei. Anbei meine Version.

    In der Datei steht z.B.:

    Brian Keene ;Eine Versammlung von Kraehen;Horror;2013;Brinkley Springs ist eine ruhige, kleine Stadt. Einige sagen, die Stadt liege im Sterben ...
    Hans Wurst;Hans Wursts Buch;Drama;1987; Ein altes Buch
    Max Mustermann;Max Mustermanns Buch;Krimi;2013; Ein neues Buch
    Beautiful Code;Andy Oram;Sachbuch;2007;How do the experts solve difficult problems in software development?
    Hans Wurst;Hans Wursts Buch;Drama;1987; Noch ein altes Buch
    Max Mustermann;Max Mustermanns Buch;Krimi;2013; Noch ein neues Buch
    Modern C++ Design;Andrei Alexandrescu;Sachbuch;2001;In Modern C++ Design, Andrei Alexandrescu opens new vistas for C++ programmers.

    Der Dialog könnte dann so aussehen:

    7 Eintraege gelesen
    
    Suchtext (Ende mit q): Wurst
    Hans Wurst; Hans Wursts Buch; Drama; 1987; Ein altes Buch
    Hans Wurst; Hans Wursts Buch; Drama; 1987; Noch ein altes Buch
     - - -
    
    Suchtext (Ende mit q): Nix
     - - -
    
    Suchtext (Ende mit q): Code
    Beautiful Code; Andy Oram; Sachbuch; 2007; How do the experts solve difficult pr
    oblems in software development?
     - - -
    
    Suchtext (Ende mit q): Buch
    Hans Wurst; Hans Wursts Buch; Drama; 1987; Ein altes Buch
    Max Mustermann; Max Mustermanns Buch; Krimi; 2013; Ein neues Buch
    Hans Wurst; Hans Wursts Buch; Drama; 1987; Noch ein altes Buch
    Max Mustermann; Max Mustermanns Buch; Krimi; 2013; Noch ein neues Buch
     - - -
    

    und hier ist das Programm dazu:

    #include <algorithm> // copy_if
    #include <iostream>
    #include <fstream>
    #include <iterator> // i/ostream_iterator
    #include <string>
    #include <limits> // numeric_limits
    #include <vector>
    
    template< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    class Buch
    {
    public:
        bool find( const std::string& suchtext ) const;
        friend std::istream& operator>>( std::istream& in, Buch& buch );
        friend std::ostream& operator<<( std::ostream& out, const Buch& buch );
    private:
        std::string autor;
        std::string titel;
        std::string genre;
        int erscheinungsjahr;
        std::string kurzbeschreibung;
    };
    
    std::istream& operator>>( std::istream& in, Buch& b )
    {   // Format: Author ;Title;Genre;Erscheinungsjahr;Zusammfassung[ ??;Bewertung]
        getline( in >> std::ws, b.autor, ';' );
        getline( in >> std::ws, b.titel, ';' );
        getline( in >> std::ws, b.genre, ';' );
        getline( in >> b.erscheinungsjahr >> Char<';'> >> std::ws, b.kurzbeschreibung );
        return in;
    }
    std::ostream& operator<<( std::ostream& out, const Buch& b )
    {
        return out << b.autor << "; " << b.titel << "; " << b.genre << "; " << b.erscheinungsjahr << "; " << b.kurzbeschreibung;
    }
    
    // --   liefert 'true', falls der Suchtext 'suchtext' in Autor, Titel oder Beschreibung vorkommt
    bool Buch::find( const std::string& suchtext ) const
    {
        return autor.find( suchtext ) != std::string::npos
            || titel.find( suchtext ) != std::string::npos
            || kurzbeschreibung.find( suchtext ) != std::string::npos;
    }
    
    int main()
    {    
        using namespace std;
        vector< Buch > buecher;
        {   // --   Einlesen
            ifstream datei("buecher.csv");
            if( !datei.is_open() )
            {
                cerr << "Fehler beim Oeffnen der Datei" << endl;
                return -2;
            }
            buecher.assign( istream_iterator< Buch >( datei ), istream_iterator< Buch >() );
            if( !datei.eof() ) // Ok, wenn EOF erreicht
                cerr << "Lesefehler" << endl;
        }
        cout << buecher.size() << " Eintraege gelesen" << endl;
        for( string such; cout << "\nSuchtext (Ende mit q): ", cin >> such && such != "q"; cout << " - - -" << endl )
            copy_if( begin(buecher), end(buecher), ostream_iterator< Buch >( cout, "\n" ), [&such]( const Buch& b ) { return b.find( such ); } );
        return 0;
    }
    

    LiinaLii schrieb:

    Evtl. ist auch mein Ansatz mit der cvs Datei nicht der beste aber mir wird einfach nicht klar wie ich es besser machen könnte oder wie es einfacher bzw. besser wäre.

    Doch - ein csv-Datei ist für so was gut geeignet. Und als Textdatei relativ einfach weiter zu verarbeiten.

    Gruß
    Werner



  • Eventuell ist aber ";" kein guter Separator, da du einen echten Fließtet drin hast und das Semicolon zwar ein seltenes, aber nicht völlig unwahrscheinliches Satzzeichen ist.

    Nimm lieber |



  • Hallo!

    Danke euch für die Ideen! Ich gucke mir das die Tage mal in Ruhe an und melde mich evtl. bei Nachfragen!



  • Hallo Leute ich bin gerade durch google auf diesen Thread gestoßen ich versuche gerade eine filmdatenbank aufzubauen und hab mir was in winforms gebastelt ich denke die Vorschläge hier wären genau das was ich brauche um das um zu setzen ich kapier nur nicht wie und wo ich das in meine forms einbauen muss ich benutze Visual Studio 2010 Express muss ich die Dateien als neue Dateien einbinden oder iwo rein kopieren oder wie kann ich die nutzen?
    Lg saywer



  • Hi!
    Ja das klingt interessant... sowas würde ich auch benötigen in etwa.. kann da jmd ein paar Tipps geben?!
    danke!



  • LiinaLii schrieb:

    Hi!
    Ja das klingt interessant... sowas würde ich auch benötigen in etwa.. kann da jmd ein paar Tipps geben?!
    danke!

    😕 Ich dachte das Problem sei gelöst. Werner hat dir doch genug Tipps gegeben?



  • saywer, komm' bitte wieder wenn du die Zeichensetzung beherrschst. So sind deine Posts eine Zumutung.

    kann da jmd ein paar Tipps geben?!

    Wenn dein Problem jetzt ist, wie du eine GUI erstellst, dann eröffne einen neuen Thread in einem entsprechenden Board.



  • hmm.. okay wenn du meinst^^



  • kann man mir da trotzdem behilflich sein?!
    wäre mega nett!!


Anmelden zum Antworten