std::istream bestimmte zeichen ignorieren



  • Hallo,

    ich möchte von einem std::istream zeichenweise lesen und dabei automatisch einige Zeichen (\n, \r, \t, Whitespace ...) ignorieren. Es gibt ja die ignore()-Funktion, aber die hilft mir bei mehreren Zeichen ja nicht wirklich weiter.

    Gibt es da eine elegante Möglichkeit sowas umzusetzen?

    Grüße



  • Nimm einfach einen geeigneten operator>>.

    Wenns UNBEDINGT zeichenweise sein muss, schau dir mal std::isspace und Konsorten an. Da wird schon was dabei sein.
    Ansonsten: Vergleichsfunktion einfach selbst schreiben:

    bool is_forbidden_character(char ch)
    {
        return (ch == '\n') || (ch == 'x') || (ch == 'a');
        // das geht natuerlich eleganter, das soll nur die Idee illustrieren.
    }
    

    Aber eigentlich klingt operator>> nach dem richtigeren Weg.





  • streamsc++ schrieb:

    ich möchte von einem std::istream zeichenweise lesen und dabei automatisch einige Zeichen (\n, \r, \t, Whitespace ...) ignorieren.

    Die Zeichen (\n, \r, \t, Whitespace ...) gehören zu den sogenannten Whitespace-Zeichen. Abhängig davon was Du liest, werden diese ohnehin ignoriert, bzw. als Trennzeichen interpretiert.
    Das geschieht immer dann wenn Du 'formatiert' liest, d.h. i.A. einen sogenannten Extraktor benutzt, was nichts anderes ist als etwa ein char , ein int , ein double oder ein Wort ( std::string ) einzulesen.

    Folgender Code würde alle Zeichen lesen - ausgenommen die Whitespace-Zeichen:

    istream in = ...;  // kann std::cin oder std::ifstream sein
        for( char c; in >> c; ) {
            ; // 'c' enthält alle Zeichen aus 'in' ausgenommen die Whitespace-Zeichen
    

    Das Überlesen von Whitespace-Zeichen kannst Du mit std::skipws/std::nospikws steuern. Die Defaulteinstellung ist skipws

    Es wäre hilfreich, wenn Du uns mitteilst was Du überhaupt lesen möchtest. Also was soll nach dem Lesen & Interpretieren später in Deinem Programm an Werten ankommen? Wie sieht das Format Deiner Datei bzw. des Input-Streams aus?

    Gruß
    Werner



  • Ich habe eine Textdatei welche ich mit einem ifstream öffne, aber generell ist es ja egal wo die Daten herkommen, deswegen istream.

    Dann habe ich eine Klasse die die Daten welche aus dem Stream extrahiert werden in Tokens (wieder eine eigene Klasse) umwandelt (generell geht es um Compilerbau). Bei der Umwandlung in ein Token muss zeichenweise gelesen werden, da je nach Zeichen in einen anderen State geswitcht wird.

    Bestimmte Zeichen sollen ignoriert werden, momentan nur die Whitespace-Zeichen, aber später vielleicht auch mal andere deswegen nicht nur auf diese Zeichengruppe beschränkt.

    Format ist z.B:

    [1, 2, nul1, null, 23k, asdf nulla]
    []
    

    Grüße


  • Mod

    Man kann Streambuffer schreiben die bestimmte Zeichen gänzlich ignorieren.

    Eine simple Implementierung ist

    template <typename CharT, typename Traits=std::char_traits<CharT>>
    class FilterBuf : public std::basic_streambuf<CharT, Traits> {
    	using base =  std::basic_streambuf<CharT, Traits>;
    	using typename base::char_type;
    	using typename base::int_type;
    	using typename base::traits_type;
    
    	base* sbf;
    	char_type ch;
    	char_type const* str;
    	std::size_t len;
    
    	int_type underflow() override {
    		if (this->gptr() < this->egptr())
    			return traits_type::to_int_type(ch);
    
    		do {
    			auto i = sbf->sbumpc();
    			if (traits_type::eq_int_type(i, traits_type::eof())) {
    				this->setg(0,0,0);
    				return i;
    			}
    			traits_type::assign(ch, traits_type::to_char_type(i));
    		} while (traits_type::find(str, len, ch));
    
    		this->setg(&ch, &ch, &ch+1);
    		return traits_type::to_int_type(ch);
    	}
    
    public:
    
    	FilterBuf( base* sbf, char_type const* str, std::size_t len )
    		: sbf(sbf), str(str), len(len) {
    		this->setg(&ch, &ch+1, &ch+1);
    	}
    };
    

    Demo.
    (Von hier übernommen, jedoch scheint die dortige Version inkorrekt zu sein)
    Das kann noch auf einen größeren Buffer erweitert werden. Das, und die Korrektur meines obigen Codes, überlasse ich jedoch Werner.


Anmelden zum Antworten