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



  • 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!!


  • Mod

    LiinaLii schrieb:

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

    Ich habe mal die relevanten Beiträge in das passende Unterforum verschoben, nachdem sich herausstellte, dass du gar kein C++ machst. Hier geht es weiter:
    http://www.c-plusplus.net/forum/319724



  • Dieser Beitrag wurde gelöscht!

Anmelden zum Antworten