Einlesen, stoppen und Einlesen



  • Ich habe mich wieder informiert, doch nichts verstädnlich/nützliches gefunden.
    gibt es einen paramter bei getline, oder eine methode bei ifstream, die es mir erlaubt nur duie letzte zeile auszulesen.
    ich habe auch schon die zeilenanzahl ausgelesen.



  • Mapper schrieb:

    gibt es einen paramter bei getline, oder eine methode bei ifstream, die es mir erlaubt nur duie letzte zeile auszulesen.

    Wenn du die Zeilenzahl hast, und bis zur letzten Zeile vorrücken willst, dann nimm istream::ignore .
    Von da wie gewohnt lesen.



  • Ich habe hier mal einen ganz anderen Weg, um die letzte Zeile einer Datei zu lesen:

    int main()
    {
    	string test( "abc\ndef\nghi\nhallo welt!" );
    	istringstream file( test );
    	string last_line;
    
    	file.seekg( 0, std::ios_base::end );
    	file.unget();
    	for( char c=0; file>>std::noskipws>>c && c!='\n'; last_line.push_back(c) )
    	{
    		file.unget();
    		file.unget();
    	}
    	std::reverse( last_line.begin(), last_line.end() );
    	cout << last_line << '\n';
    }
    

    Was haltet ihr davon? Ist das ineffizient? Falls ja, was wäre ein effizienter Weg, die letzte Zeile zu lesen?



  • Ich hätte soetwas verwendet:

    #include <iostream>
    #include <string>
    
    int main()
    {
        std::istream file(std::cin.rdbuf());
    
        std::string last_line;
        while (std::getline(file, last_line))
            ;
        std::cout << last_line;
    }
    

    Aber ich glaube, das ist zu banal. :p
    Außerdem ist outs Lösung effizienter.

    Edit: Das reverse Lesen ist aber schon ein wenig unhandlich. Sone, schreib' mal nen streambuf der rückwärts liest. 😉



  • #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