'streambuf::underflow' überschreiben, um Kommentare auszufiltern



  • Hallo,

    Ich versuche, beim Lesen über 'std::getline' transparent Kommentare aus dem gelesenen Stream herauszufiltern. Kommentare starten mit '#' und gehen bis zum Ende der Zeile.

    Werner hatte hier ja schon öfters Codes gepostet, in denen 'std::streambuf' erweitert und 'underflow' überschrieben wird, um sowas in der Art zu erreichen. Leider finde ich gerade nichts passendes und komme auch mithilfe der Doku nicht weiter. Welche Möglichkeiten zur Manipulation des gelesenen Streams habe ich hier denn?



  • hola

    vielleicht funktioniert es so:

    class my_buf : public std::filebuf
    {
       public:
          typedef std::filebuf::int_type int_type;
          virtual int_type uflow(void)
          {
             int_type c = filebuf::uflow();
             if(static_cast<char>(c) == '#')
             {
                while((c = gnextc()) != EOF && c != '\n');
             }
    
             return c;
          }
    }
    

    Meep Meep



  • Konrad Rudolph schrieb:

    Werner hatte hier ja schon öfters Codes gepostet, in denen 'std::streambuf' erweitert und 'underflow' überschrieben wird, um sowas in der Art zu erreichen.

    Hallo Konrad,

    streambuf erweitern ja, aber mit Filter-Funktion ... daran kann ich mich nicht erinnern. Ich würde Dir entweder was in der Art vorschlagen:

    #include <iostream>
    #include <cassert>
    #include <streambuf>
    #include <sstream>
    
    class CommentFilter : public std::streambuf
    {
    public:
        explicit CommentFilter( std::streambuf* sb )
            : base_type()
            , m_c()
            , m_target( sb )
        {
            assert( m_target );
        }
    protected:
        virtual int_type underflow()
        {
            bool comment = false;
            for( int_type m = m_target->sbumpc();; m = m_target->sbumpc() )
            {
                if( traits_type::eq_int_type( m, traits_type::eof() ) )
                    return traits_type::eof();
                const char c = traits_type::to_char_type( m );
                if( comment )
                {
                    if( c == '\n' )
                        comment = false;
                    else
                        continue;
                }
                if( c != '#' )
                {
                    m_c = c;
                    setg( &m_c, &m_c, &m_c + 1 );
                    return m;
                }
                comment = true;
            }
        }
    
    private:
        typedef std::streambuf base_type;
        char m_c;   // das letzte gelesene Zeichen
        std::streambuf* m_target;
    };
    
    int main()
    {
        using namespace std;
        istringstream buf("1.Zeile\n2.Zeile#kommentar\n3.Zeile\n");
        CommentFilter flt( buf.rdbuf() );
        istream in( &flt );
        cout << in.rdbuf() << "-- ende --" << endl;   // hier ginge natürlich auch: cout << &flt;
        return 0;
    }
    

    oder Du schaust Dir mal die boost-iostreams an. Die bieten auch Filter an. Ich habe das selber aber noch nicht benutzt.

    Gruß
    Werner



  • Hallo,

    vielen Dank an euch beide, das ist gut. Boost bietet sich in diesem Fall nicht an, obowhl ich generell immer dafür bin, Boost-Lösungen zu verwenden.


Anmelden zum Antworten