(Wunschliste) txt Dateiformat Design/Auslesen - Verbessern



  • Hallo zusammen,

    ich möchte mehrere Einträge in eine .txt Datei speichern, wobei ein Eintrag besteht aus:
    - Name (required)
    - Date (YYYY-MM-DD, optional aber direkt in der Zeile nach dem Namen)
    - Beliebige Anzahl Textzeilen (Wunschliste)

    Das gute ist, ich benutzte eine kleine date.h lib von github, die mir u. a. das Parsen des Datums abnimmt.

    Dabei habe ich bisher folgendes Format:
    ';' -> Rest der Zeile gehört zum Name -> suchen nach '>' -> falls vorhanden Datum lesen -> bis zur nächsten ';' Zeile den Text einlesen.

    Bsp:

    ;Max Mustermann
    >0000-01-01          // kein Geburtsjahr vorhanden, bday am 1. Jan
    Wunsch1
    Wunsch2
    Wunsch3
    

    Folgender Code ließt die Dateien aus

    struct Person {
        date::year_month_day bday;// year 0 means no birthyear known
        std::vector<std::string> wishes;
    };
    
    std::map<std::string, Person> wishlist;
    
    void Wishlist::read(std::istream& is)
    {
        unsigned nlines{1};
        std::string name;
        for (std::string line;
             std::getline(is >> std::ws, line);
             ++nlines)
        {   // line can't be empty because of is >> std::ws
            if (line.front() == ';')
            {
                if (line.size() < 2)
                    error("Expected name after ; (line " + std::to_string(nlines) + ")");
    
                name = line.substr(1, line.size() - 1);
                wishlist[name] = {};
    
                if ((is >> std::ws).get() == '>')
                {
                    ++nlines; // date starts on new line
                    if (!(is >> date::parse("%F", wishlist[name].bday))) // YYYY-MM-DD
                        error("Invalid date (line " + std::to_string(nlines) + ")");
                }
                else
                    is.unget();
            }
            else if (name.size())
                wishlist[name].wishes.push_back(line);
            // else
               // header += line;
        }
    }
    

    Meine Frage(n) nun:
    A: Gäbe es für mein Problem ein besseres Format (.txt)
    B: Ließe sich das Dateiformat geschickter/besser auslesen? Ich habe mich sehr bemüht nicht etwas zu lesen, dann einen istringstream daraus zu machen, und dann noch mal daraus zu lesen.

    Vielen Dank im Voraus

    LG



  • Man muss unterscheiden, ob die Datei auch "von Hand" geändert werden soll. Wenn nein, ist es im Grunde egal, dann kannst du aber auch gleich ein Binärformat nehmen.
    Wenn ja, ist der Aufbau alles andere als intuitiv: Namen und Datum müssen zwingend Zeichen vorangestellt werden und das Datumsformat ist abenfalls nicht allgemein gebräuchlich.
    Auch lässt es sich schwer erweitern, was ist, wenn statt Wünschen auch andere Sachen wie Hobbys etc. angegeben werden sollen?
    Ohne jetzt den xml-Hammer hervorzuholen kennst du doch mit Sicherheit "private profile strings":

    [name1]
    bthd=2.9.34
    wishes=.....; entweder wishesXX= oder durch tokens getrennt
    ...
    ...
    [name2]
    ...
    

    Für den gelegentlichen Hausgebrauch finde ich so etwas gar nicht mal schlecht. Leicht zu editieren, einfach einzulesen und durhc die Sektionen auch leicht erweiterbar.



  • Hallo,

    vielen Dank für deine Antwort.

    Was die Erweiterbarkeit angeht, daran hatte ich garnicht gedacht, ist aber eigentlich schon ein wichtiges Kriterium. Eigentlich macht es ja gar keinen Sinn etwas eigenes zu Schmieden, wenn es doch - wie schon erwähnt - XML, JSON etc. gibt.
    Edit: Wobei, so eine JSON header-only lib hat mal schnell über 13k Zeilen, was bei einem <1k Zeiler ziemlich overkill erscheint.

    Finde deinen INI-ähnlichen Vorschlag nicht schlecht, das einzige Problem ist ich wollte eigentlich verhindern Zeichenweise zu lesen.


Anmelden zum Antworten