Ini-Dateien parsen



  • Boost::Spirit sieht interessant aus, aber ich glaube das wäre ein wenig überdimensioniert für meine Zwecke, aber ich werds mal damit ausprobieren.

    @hustbaer: Wie sollten denn die Klassen IniFileParser und IniFile dann aussehen? (Welche Methoden brauchen Sie) und wie funktioniert das mit der State-Machine?



  • Rein zufällig behandelt der Spirit-Artikel von Tobias Gerg im Forums-Magazin auch das Parsen von ini-Dateien. 😃



  • Hallo

    Artchi schrieb:

    Rein zufällig behandelt der Spirit-Artikel von Tobias Gerg im Forums-Magazin auch das Parsen von ini-Dateien. 😃

    Darum geht es ja unter anderem und der Link wurde auch schon gezeigt. 😕

    chrische



  • Ups!



  • OhneName schrieb:

    Boost::Spirit sieht interessant aus, aber ich glaube das wäre ein wenig überdimensioniert für meine Zwecke, aber ich werds mal damit ausprobieren.

    @hustbaer: Wie sollten denn die Klassen IniFileParser und IniFile dann aussehen? (Welche Methoden brauchen Sie) und wie funktioniert das mit der State-Machine?

    Naja, kommt drauf an ob man lieber Templates oder lieber Interfaces verwendet. Hier mal die Version mit nem Interface:

    class IniFileParser
    {
    public:
        class Client
        {
        public:
            virtual void ProcessSectionHeader(std::string const& sectionName) = 0;
            virtual void ProcessValue(std::string const& sectionName, std::string const& valueName, std::string const& value) = 0;
            // virtual void ProcessComment(std::string const& comment) = 0;
        };
    
        explicit IniFileParser(Client* client);
    
        void SetClient(Client* client);
    
        bool ProcessStream(std::istream& is);
        bool ProcessChar(char c);
        void Flush();
    
        // ...
    };
    
    class IniFile : private IniFileParser::Client
    {
    public:
        explicit IniFile(std::string const& path)
        {
            IniFileParser parser(this);
            parser.ProcessStream(std::ifstream(path));
            parser.Flush();
        }
    
    private:
        virtual void ProcessSectionHeader(std::string const& sectionName);
        virtual void ProcessValue(std::string const& sectionName, std::string const& valueName, std::string const& value);
    
        // ...
    };
    


  • hustbaer schrieb:

    Naja, kommt drauf an ob man lieber Templates oder lieber Interfaces verwendet.

    Kanonen auf Spatzen schießen?



  • Mr. N schrieb:

    hustbaer schrieb:

    Naja, kommt drauf an ob man lieber Templates oder lieber Interfaces verwendet.

    Kanonen auf Spatzen schießen?

    Huch?
    Der OP hat gemeint es stört ihn dass der gesamte Parser im ctor "enthalten" ist. Ich hab' ihm einen halbwegs sauberen Weg gezeigt das zu vermeiden.
    Wenn du das Interface meinst: was genau ist daran schlecht? Bzw. wo ist die "Kanone" - die 10 Zeilen Code die das mehr ausmacht? Naja...

    Strenggenommen ist schon die Verwendung von IniFileParser im ctor von IniFile unnötig und sollte vermieden werden, z.B. durch eine free function "LoadIniFile" die genau die beiden Klassen zusammenknotet. Ich wollte es dann aber auch nicht übertreiben...

    Ich würde es eher als Kanonen auf Spatzen schiessen bezeichnen jmd. der damit noch offensichtlich keine Erfahrung hat die Verwendung von Boost.Spirit zu empfehlen.



  • Hallo, ich lebe hinter dem Mond und würde gern wissen, wozu man Ini Dateien parsen tut.

    MfG
    DhMl



  • Vielen Dank für das Beispiel, hustbaer.

    Ich versuch das ganze jetzt erst mal mit Boost::Spirit umzusetzen, der Magazinartikel erklärt das eigentlich recht gut und ich hab die Boost-Biblioteken sowieso schon auf meinem Rechner.

    Anschließend schau ich mir auch deinen Vorschlag nochmal genauer an.

    @Der hinterm Mond lebt:
    Ich brauche ein Dateiformat um leicht Einstellungen speichern und lesen zu können. Die Windows-Registry will ich nicht verwenden und ein eigenes Format entwickeln auch nicht. Also hab ich erstmal INI gewählt, da XML doch noch ein ganzes Stück schwerer zu parsen ist. Wie eine Ini-Datei aufgebaut ist, habe ich in meinem ersten Post kurz dargestellt.



  • hustbaer schrieb:

    Mr. N schrieb:

    hustbaer schrieb:

    Naja, kommt drauf an ob man lieber Templates oder lieber Interfaces verwendet.

    Kanonen auf Spatzen schießen?

    Huch?
    Der OP hat gemeint es stört ihn dass der gesamte Parser im ctor "enthalten" ist. Ich hab' ihm einen halbwegs sauberen Weg gezeigt das zu vermeiden.
    Wenn du das Interface meinst: was genau ist daran schlecht? Bzw. wo ist die "Kanone" - die 10 Zeilen Code die das mehr ausmacht? Naja...

    Dein Weg ist natürlich nicht falsch, aber eben unnötig kompliziert. Ich würde auch kein Spirit verwenden. Aufteilen des Parsers in ein paar Methoden und Verwendung dessen, was der Standard und Boost.String_algo hergibt, und schon sieht das ganze viel schöner aus. 🙂

    Ich habe für einen Parser mit einem ähnlichen aber einfacheren Format (nur Key=Value und Kommentare mit 😵 etwa 40 Zeilen gebraucht und ich habe keine externe Bibliothek verwendet. (Hat mich sehr geärgert, dass die Boost-Abhängigkeit in meiner Abwesenheit rausgestrichen wurde. 🙄)

    OhneName schrieb:

    Also hab ich erstmal INI gewählt, da XML doch noch ein ganzes Stück schwerer zu parsen ist.

    Sicher, dass du Sektionen brauchst?



  • Mr. N schrieb:

    OhneName schrieb:

    Also hab ich erstmal INI gewählt, da XML doch noch ein ganzes Stück schwerer zu parsen ist.

    Sicher, dass du Sektionen brauchst?

    Das ist eine interessante Idee, weil eigentlich brauch ich sie nicht, und würde das ganze mit Sicherheit deutlich vereinfachen, doch wenn ich schonmal nen Parser schreib, dann auch gleich richtig. Ich hatte in meiner ursprünglichen Version ja auch bereits Unterstützung für Tabs und Leerzeichen eingebaut um Einrückung möglich zu machen.

    Also dank des großartigen Magazinartikels habe ich jetzt schonmal einen laufenden Parser mit Boost::Spirit. So schwierig find ich die Bibliothek garnicht, das Problem sind eher ein paar Unterschiede im Programmierstil zwischen mir und dem Autor (vorallem bei Variablennamen). Aber wenn ich das ganze erstmal an meine "Stil" angepasst habe, dann werd ich wohl bei dieser Lösung bleiben. Ich poste die fertige Klasse dann wieder hier.



  • Unter http://alphadev.awardspace.com/index.html könnt ihr euch nun das fertige Ergebnis ansehen. Ich bin eigentlich recht zufrieden damit und hab auch noch ein paar mehr Features drin als in der ursprünglichen Version.

    Jetzt würde mich interessieren:
    - Ist es sinnvoll boost::lexical_cast zu verwenden um Werte beliebigen Typs auszulesen?
    - Ist es okay, dass der Funktor GetData und das Struct Entry als innere Klassen des IniFileParsers implementiert sind oder sollte ich das besser trennen?
    - Gibt es eine bessere Lösung um die geparsten Werte in meiner Map zu speichern, als über das Struct Entry?

    Schonmal danke im Voraus für jegliche Kritik 🙂


Anmelden zum Antworten