Ersetzen des Whitspace als Trennzeichen beim Auslesen aus Datei durch Semikolon



  • Ich weiß, zu dem Thema gibt es ähnliche Fragestellungen, aber ich verstehe die Lösungsansätze nicht ganz. Deshalb stell ich hier meine Frage nochmal:
    Ich habe eine Datei, welche Daten mit Semikolon abtrennt. Ich würde gerne die Daten mit der Funktion getline() einlesen. Ich habe bisher immer die Semikolon durch Leerzeichen ersetzt und dann Zeile für Zeile eingelesen, da dann ja das Leerzeichen als Trenner zwischen den einzelnen streams funktionierte. Dies wird ja im Forum als Low-Tech-Lösung bezeichnet.
    Beispiel.Txt:

    5;7;3.34
    6;8;2.78
    3;2;8.2

    Was kann ich machen, um das Semikolon als Trenner zu verwenden? Werner Salomon scheint ja hier der Experte zu sein, allerdings verstehe ich nicht immer, was er da im einzelnen macht. In einem Beitrag habe ich gesehen, dass

    template< char C >
    struct Char // Helferlein zum Lesen des ';' (s.u.)
    {
        friend std::istream& operator>>( std::istream& in, const Char )
        {
            char c;
            if( in >> c && c != C )
                in.setstate( std::ios_base::failbit );
            return in;
        }
    };
    

    Wenn ich das richtig verstehe wird hier ein Template geschrieben um später das das failbit durch ein Semikolon zu ersetzen.
    Aber ich habe noch das Problem, dass ich nicht verstehe wie ich das im späteren verwende 😕

    kann mir bitte jemand auf die Sprünge helfen?
    hier mal mein Beispielcode:

    // wie kann ich das Template nutzen? - ist es für meinen Fall überhaupt Sinnvoll? - bzw. gibt es eine andere Lösung?
    int main()
    {
        ifstream datei ("Beispiel.txt");
        string zeile;
        while(getline(datei, zeile))
        {
            stringstream zeilenpuffer(zeile);
            int aa;
            int bb;
            double cc;
    
            zeilenpuffer >> aa >> bb >> cce; // liest immer nur bis aa richtig ein
            cout << aa << " ; " << bb << " ; " << cc << " ; "endl;
    }
    


  • Du kannst getline mitteilen, dass nicht newline, sondern zB. das Semikolon als Trenner benutzt werden soll:
    http://www.cplusplus.com/reference/string/string/getline/



  • @ Belli

    vielleicht habe ich micht unverständlich ausgedrückt?

    Durch

    getline(datei, zeile, ';')
    

    rutsche ich doch beim auslesen in die nächste Zeile und nicht in die nächste "Spalte". Ich will ja aber auch noch die 5 und die 3.34 der ersten Zeile auslesen (Spalte 2 + 3).
    Oder meinst du was anderes?



  • Hallo Thomas,

    willkommen im C++-Forum.

    Thomas1999 schrieb:

    Ich habe eine Datei, welche Daten mit Semikolon abtrennt. Ich würde gerne die Daten mit der Funktion getline() einlesen.

    Warum immer nur 'getline'? Suche mal hier im Forum nach 'getline ist doof'.

    Thomas1999 schrieb:

    Werner Salomon scheint ja hier der Experte zu sein,

    Na ja .. mit vielleicht etwas mehr Erfahrung als andere.

    Thomas1999 schrieb:

    allerdings verstehe ich nicht immer, was er da im einzelnen macht.

    Dann stell' konkrete Fragen .. so wie hier jetzt.

    Thomas1999 schrieb:

    In einem Beitrag habe ich gesehen, dass

    template< char C >
    struct Char // Helferlein zum Lesen des ';' (s.u.)
    {
        friend std::istream& operator>>( std::istream& in, const Char )
        {
            char c;
            if( in >> c && c != C )
                in.setstate( std::ios_base::failbit );
            return in;
        }
    };
    

    das ist aber eine SEHR alte Variante von ' Char<> '. Aus welchem Thread hast Du die?

    Aktuelle sähe das so aus:

    // --   Helferlein zum Überlesen eines Zeichens 'C'
    template< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    

    Das ist ein Funktionstemplate. Also eine Funktion, die einen std::istream& annimmnt und den gleichen wieder zurück liefert. Man muss dazu wissen, dass std::istream eine Methode hat, deren Parameter genau so ein Funktionstyp ist. Siehe dazu http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ unter manipulators (3).
    Da ich so einer Funktion keinen zweiten Parameter mitgeben kann, habe ich die Konstruktion mit dem Template gewählt. Das gewünschte Zeichen wird als Template Parameter mitgegeben.
    Die Anwendung sähe so aus:

    int a;
        if( cin >> Char<';'> >> a )  // gebe hier z.B.: ";4711" ein
            cout << "; und int = " << a << gelesen;
    

    Die Funktion liest ein Zeichen ' in >> c ' und prüft anschliend ob das Zeichen sich von C unterscheidet '.. && c != C'. Ist dies der Fall, stimmt das Format nicht, also wird das Fehlerflag gesetzt und damit endet jede weitere Eingabe.

    Dein Code könnte dann z.B. so aussehen:

    int main()
    {
        ifstream datei ("Beispiel.txt");
        // prüfe hier noch, ob die Datei offen ist!
        int aa;
        int bb;
        double cc;
        while( datei >> aa >> Char<';'> >> bb >> Char<';'> >> cc )
        {
            cout << aa << " ; " << bb << " ; " << cc << " ; " << endl;
        }
    }
    

    Gruß
    Werner



  • Hallo Werner,

    ich weiß nicht ob man sich hier im Forum bedankt oder es weglässt, weil es keiner lesen will.
    Ich möchte mich jedenfalls bedanken! Mein Problem ist gelöst und deine Erklärung und die Verweise haben mein Verständnis schon ein bisschen erhöht. Ich werde mich aber noch weiter einlesen. Ob du es glaubst oder nicht - das meiste hatte ich schon gefunden (hatte wirklich ausführlich das Forum und die c++reference gewälzt, aber nicht verstanden wie ich was nutzen kann weil ja oft auf ähniche Probleme unterschiedliche Lösungen präsentiert werden die aber natürlich nicht immer zusammen passen (das ist mir bewusst). Deshalb fand ich deine kurze Erklärungen besonders hilfreich (Hilfe zur Selbsthilfe)

    Ich lerne das Programmieren alleine (versuche es zumindest) und da ist jemand wie du ne große Hilfe! Denn meine ganze C++ Bücher sind voller Wissen, erschlagen einen aber vor lauter Komplexität auch gerne - und in meiner Umgebung ist niemand mit dem man sich austauschen und auch mal kleinere Fragen stellen kann. Das löst so manche Lern- und Verständnisblockade und motiviert weiter zu machen. Und gerade die Arbeit mit den ganzen Funktionen der einzelnen Referenzen zieht einem Anfänger oft die Latschen aus, weil ein kleiner Fehler im Verständnis ja alles über den Haufen wirft 😮 .

    In jedem Fall
    Besten Dank 😃

    PS: Die Suche nach "getline ist doof" ergab keinen Treffer, aber vielleicht spinnt die Suchfunktion gerade 😉



  • Hallo Thomas,

    Thomas1999 schrieb:

    ich weiß nicht ob man sich hier im Forum bedankt oder es weg lässt, weil es keiner lesen will.

    doch doch ... bedanken ist immer gut und erhöht die Motivation der Antwortenden ungemein. Ansonsten ist auch jede Art von konstruktivem Feedback willkommen.

    Thomas1999 schrieb:

    PS: Die Suche nach "getline ist doof" ergab keinen Treffer, aber vielleicht spinnt die Suchfunktion gerade 😉

    Du hast die SuFu aus dem Forum benutzt. Die funktioniert nicht. Probiere Google: site:c-plusplus.net "getline ist doof"

    Gruß
    Werner


Anmelden zum Antworten