Einlesen, stoppen und Einlesen



  • #include <iostream>
    #include <sstream>
    #include <iterator>
    
    int main()
    {
        std::istringstream file( "abc\nbcd\nhallo welt!" );
    
        file.seekg( 0, std::ios_base::end );
    
        char c;
        do c = file.rdbuf()->sungetc();
        while( c != '\n' && c != std::char_traits<char>::eof() );
    
        std::string last_line;
    
        if( c == '\n' )
            last_line.assign( ++std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() );
    
        std::cout << last_line << '\n';
    }
    

    🤡

    Edit:

    Nathan schrieb:

    Sone, schreib' mal nen streambuf der rückwärts liest. 😉

    Ohne Witz, ich hab das nicht gelesen! Ich hab das gerade erst entdeckt! 😃



  • Sowas wie getline magste nicht, oder?



  • Nathan schrieb:

    Sowas wie getline magste nicht, oder?

    Ich?
    Doch.



  • Die Zeile ersetzen:

    if( c == '\n' )
            std::getline( file.ignore(), last_line, char(EOF) );
    

    Edit: Zur Konformität nehm' ich mal EOF.



  • Genau das meinte ich.
    Hat das einen besonderen Grund warum du sungetc() verwendest anstatt ungetc des Streams?
    Edit: Und dein file.seekg() kannste durch ignore ersetzen, weniger zu schreiben.



  • Nathan schrieb:

    Edit: Und dein file.seekg() kannste durch ignore ersetzen, weniger zu schreiben.

    Wirklich. Ohne Witz. Hab ich gerade gemacht, da sehe ich deine Antwort.

    ungetc kannte ich nicht. 👍

    Edit: Was für ein ungetc? 😕



  • Klar kannte ich das noch nicht -
    das gibt es ja auch gar nicht.



  • Sone schrieb:

    char(EOF)

    Also echt, du hast ja gar keine Ahnung ...

    Es gibt einen Grund, dass getchar() int und nicht char zurückgibt.
    Es gibt einen Grund, dass es einen char_type und einen int_type gibt.
    Es gibt einen Grund, dass EOF kein gültiger unsigned char ist.
    Versuche mal, dahinter zu kommen.



  • Sone schrieb:

    Klar kannte ich das noch nicht -
    das gibt es ja auch gar nicht.

    Sorry, meinte unget() von std::basic_istream.



  • Satan: Soll das ein Scherz sein?
    Ich kann nicht einfach EOF schreiben, das geht nicht. Da gibt es Fehler bei der Deduktion des Arguments. Und die template-parameter-list explizit hinzuschreiben würde den gleichen Cast erzwingen.
    Soll ich jetzt
    std::char_traits<char>::to_char_type( std::char_traits<char>::eof() )
    schreiben, wenn ich einfach EOF als char haben möchte?

    Nathan schrieb:

    Sone schrieb:

    Klar kannte ich das noch nicht -
    das gibt es ja auch gar nicht.

    Sorry, meinte unget() von std::basic_istream.

    Aber dann ist die Version nicht so elegant wie durch einen Methodenaufruf.
    file.unget().peek() vs file.rdbuf()->sungetc() .

    Edit: to_char_type natürlich.





  • Sone schrieb:

    Satan schrieb:

    Versuche mal, dahinter zu kommen.

    Unabhängigkeit vom Zeichentyp.

    Sone schrieb:

    Soll ich jetzt
    std::char_traits<char>::to_char_type( std::char_traits<char>::eof() )
    schreiben, wenn ich einfach EOF als char haben möchte?

    Nein.

    Jeder Wert eines char kann potentiell in einer Datei vorkommen. (char)EOF darf in jeder Datei vorkommen.

    Deshalb gibt getchar() und sgetc() ein int zurück: Wenn der Wert zwischen 0 und 256 ist, war er so in der Datei. Wenn er ausserhalb davon liegt, trat irgend ein Fehler auf. Bei -1 EOF z.B. Wenn du EOF zu einem char castest, wird (char)EOF, was ja ein gültiges Zeichen sein kann, fälschlicherweise als EOF erkannt.

    Kurz: std::char_traits<char>::eof() ist einer der Werte, die nicht als char_type dargestellt werden können, ihn zu einem solchen casten zu wollen ist schlicht falsch.



  • Satan schrieb:

    Kurz: std::char_traits<char>::eof() ist einer der Werte, die nicht als char_type dargestellt werden können, ihn zu einem solchen casten zu wollen ist schlicht falsch.

    Völlig richtig. Daher ist getline hier nicht nur Fehl am Platz, sondern der von mir gepostete Code sollte gar nicht funktionieren.
    Aber eine Variante, so fällt mir gerade auf, gibt es auch mit getline:

    std::getline( file.ignore(), last_line, '\n' ); // Es wird keinen Zeilenumbruch mehr geben
    

    Natürlich ist da ein unnötiger Vergleich inbegriffen, aber was solls. Persönlich finde ich die Variante mit den streambuf-Iteratoren schöner.


Anmelden zum Antworten