Eingabedatei nach Begriffen durchsuchen



  • Hallo zusammen,
    ich lerne grade im ersten Semster C++ und habe eine Frage bezüglich der folgenden Aufgabe.
    Ich habe eine Datei mit vielen Büchern die immer Blockweise aufgelistet sind. Die Datei sieht ungefähr so aus:

    Titel=Blablablabla
    Ort=blabla
    Autor=blabla

    Titel=Blububub
    Ort=blubub
    Autor=blabub
    Jahr=1998

    Titel=Bfddff
    Ort=sfdsdf

    usw..

    Ich will die Datei einlesen und dann nach bestimmten Wörtern suchen. Gebe ich bei der Suche beispielsweise "Ort" und "Berlin" ein, sollen alle Bücher ausgegeben werden, bei denen der Ort Berlin ist.

    Mein Problem ist nun, dass ich zwar die Zeile ausgegeben bekomme, in der "Ort=Berlin" in der Datei steht, aber nicht den Titel, Autor und was sonst noch dabei steht.

    Wäre nett wenn Ihr mir helfen könntet.



  • Du stellst keine Frage.



  • Da reichen Zeilen wohl nicht aus. Aber da gibt's ja noch die Blöcke.



  • Wie kann ich die Datei denn blockweise einlesen?



  • Woran merkt man, dass ein Block zu ende ist?



  • Von der Idee her ist das klar, einlesen bis eine Leerzeile kommt und dann in einer Variable speichern um diese dann zu überprüfen. Aber es funktioniert nicht so wie ich will und da ich noch ein Anfänger bin, bin ich mir mit der Syntax nicht sicher.

    Wie kann ich denn die eingelesene Zeile in eine Variable speichern, bis eine Leerzeile kommt?



  • CppNeuling schrieb:

    Wie kann ich denn die eingelesene Zeile in eine Variable speichern, bis eine Leerzeile kommt?

    Wie speicherst du denn jetzt die Zeilen?
    Datenstrukturen kann man verschachteln.



  • @CppNeuling
    Wenn du dir bei der Syntax nicht sicher bist, dann beschreib doch mal einfach mit Worten was du dein Programm machen lassen möchtest. Schritt für Schritt, genau so ausführlich wie man es programmieren würde.
    Dann übersetzt das nach C++ was du kannst. Beim Rest kannst du ja fragen.



  • Ich lese momentan nur Zeile für Zeile ein.

    istringstream stream(speicher);

    while(getline(stream, line)) {

    }

    und dann würde ich gerne einlesen bis eine Leerzeile kommt und das eingelesene in eine Variable speichern, die ich dann auf das vom User eingegebene Wort untersuchen kann. Dann soll bis zum nächsten Leerzeichen gelesen und abgespeichert werden, sodass der nächste Abschnitt auch auf das Wort untersucht werden kann usw.
    Am Schluss sollen dann alle Büchern ausgegeben werden, die das eingegebene Wort des Users erhalten.



  • Hier ein Beispiel:

    book.hpp

    #ifndef BOOK_HPP
    #define BOOK_HPP
    
    #include <string>
    #include <iosfwd>
    
    struct Book
    {
        std::string title;
        std::string location;
        std::string author;
        int year = 0;
    };
    
    std::ostream& operator<<(std::ostream& os, const Book& book);
    std::istream& operator>>(std::istream& is, Book& book);
    
    #endif
    

    book.cpp

    #include "book.hpp"
    
    #include <ostream>
    #include <istream>
    #include <sstream>
    #include <utility>
    
    namespace
    {
        const auto Delimiter = '=';
    
        const std::string Title_Key = "Titel";
        const std::string Location_Key = "Ort";
        const std::string Author_Key = "Autor";
        const std::string Year_Key = "Jahr";
    }
    
    std::ostream& operator<<(std::ostream& os, const Book& book)
    {
        os << Title_Key << Delimiter << book.title << "\n";
        os << Location_Key << Delimiter << book.location << "\n";
        os << Author_Key << Delimiter << book.author << "\n";
        os << Year_Key << Delimiter << book.year << "\n";
    
        return os;
    }
    
    std::istream& operator>>(std::istream& is, Book& book)
    {
        Book temp;
    
        std::string line;
    
        while (std::getline(is, line))
        {
            if (line.empty())
            {
                book = std::move(temp);
                break;
            }
    
            std::istringstream iss(line);
            std::string key;
            if (std::getline(iss, key, Delimiter))
            {
                if (key == Title_Key)
                {
                    std::getline(iss, temp.title);
                }
                else if (key == Location_Key)
                {
                    std::getline(iss, temp.location);
                }
                else if (key == Author_Key)
                {
                    std::getline(iss, temp.author);
                }
                else if (key == Year_Key)
                {
                    iss >> temp.year;
                }
            }
        }
    
        return is;
    }
    

    main.cpp

    #include "book.hpp"
    
    #include <fstream>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <iterator>
    
    int main()
    {
        setlocale(LC_ALL, "");
    
        std::ifstream file("Bücher.txt");
    
        if (!file)
        {
            std::cerr << "Die Datei kann nicht geöffnet werden\n";
    
            return 1;
        }
    
        std::vector<Book> books;
    
        std::copy(
            std::istream_iterator<Book>(file),
            std::istream_iterator<Book>(),
            std::back_inserter(books));
    
        std::cout << "Die Datei enthält " << books.size() << " Bücher\n";
    
        std::cout << "Alle Bücher der 90er Jahre:\n";
    
        std::copy_if(begin(books), end(books), std::ostream_iterator<Book>(std::cout),
            [] (const Book& book) { return book.year >= 1990 && book.year < 2000; });
    
        std::cout << "Alle Bücher mit unbekanntem Autor:\n";
    
        std::copy_if(begin(books), end(books), std::ostream_iterator<Book>(std::cout),
            [] (const Book& book) { return book.author.empty(); });
    }
    

    Vielleicht kann mir jmd. noch zeigen, wie man den Zwischenschritt über den std::istringstream vermeiden kann. Ich scheiterte daran, dass beim Einlesen bis zum nächsten = die leeren Zeilen "verschluckt" wurden.



  • theta - WTF?


Anmelden zum Antworten