read until



  • Ich suche eine Funktion mit der ich einen Stringstream so lange auslesen kann, bis er ein bestimmtes Wort findet.

    Leider funktioniert das mit std::getline nicht weil er nur ein char erwartet 😞



  • Folgender Ansatz:

    std::istream& read_until(std::istream &is, std::string &value, const std::string &delimiter)
    {
    	value.clear();
    	while (true)
    	{
    		// alles bis zum ersten Zeichen von delimiter einlesen
    		std::string tmp;
    		if (!std::getline(is, tmp, delimiter[0]))
    			return is;
    		// das Eingelesene anfügen
    		value += tmp;
    
    		// prüfen, ob nachfolgende Zeichen passen
    		auto is_delim = true;
    		std::string delim_so_far;
    		for (auto i = 1u; i < delimiter.size(); ++i)
    			if (is.peek() == delimiter[i])
    				delim_so_far.push_back(is.get()); // für den Fehlerfall speichern
    			else
    			{
    				is_delim = false;
    				break;
    			}
    		if (is_delim)
    			break;
    		else
    			value += delim_so_far; // die Zeichen vom Pseudodelimiter anfügen
    	}
    
    	return is;
    }
    

    Geht ggf. auch effizienter.



  • Definiere "so lange auslesen bis er ein bestimmtes Wort findet".
    Vielleicht mit Hilfe eines Beispiels.

    Da gibt's nämlich mehrere Möglichkeiten wie man das verstehen kann.



  • Eine eigene Funktion kann ich selbst schreiben, aber ich dachte das es für so etwas zumindest in boost eine Lösung gibt.

    Es geht darum eine HTML Datei in verschiedene Bereiche einzteilen. Der Header endet mit "/n/r/n/r" und bis dahin will ich lesen.

    while( std::getline( ss, str ) )
    {
        if( str.find("\n\r\n\r") )
    }
    

    Das würde mir schon reichen aber ich wollte keine eigene Funktion schreiben.



  • Wenn ich mich richtig erinnere endet ne HTTP Header (falls du die meinst - ne HTML Datei hat nämlich keine Header) mit \r\n\r\n . Also genau umgekehrt.

    Und ich kenne leider auch keine fertige Funktion mit der man das machen kann.
    Wieso liest du nicht die ganze Datei in einen std::string und suchst dann mit string::find ?



  • Danke daran habe ich nicht gedacht 😃

    auto pos = data.find("\r\n\r\n");
    if( pos == std::string::npos )
        throw std::runtime_error("HttpFile: header not found");
    
    head = data.substr(0, pos);
    body = data.substr(pos, data.length()));
    


  • exploit126 schrieb:

    Das würde mir schon reichen aber ich wollte keine eigene Funktion schreiben.

    Wieso nicht? Einmal erledigt, hast du dein read_until() für den Rest deiner C++-Karriere.



  • hustbaer schrieb:

    Wieso liest du nicht die ganze Datei in einen std::string und suchst dann mit string::find ?

    weil das gar nicht notwendig ist.

    Vorschlag:

    #include <string>
    #include <iostream>
    #include <iterator> // istream_iterator
    #include <algorithm> // std::find
    
    struct read_until
    {
        explicit read_until( const std::string& key )
            : key_( key )
        {}
        friend std::istream& operator>>( std::istream& in, read_until ru )
        {
            std::find( std::istream_iterator< std::string >( in ), std::istream_iterator< std::string >(), ru.key_ );
            return in;
        }
    private:
        std::string key_;
    };
    
    // -- Demonstration zur Anwendung von 'read_until'
    int main()
    {
        using namespace std;
        cout << "geben sie einen Satz mit 'hier' ein und dahinter einen  Zahl\n";
        for( int zahl; cout << "> ", cin >> read_until("hier") >> zahl; cin.ignore( 999, '\n' ) )
            cout << "Die Zahl ist: " << zahl << endl;
        return 0;
    }
    

    Der Dialog wäre dann z.B.:

    geben sie einen Satz mit 'hier' ein und dahinter einen  Zahl
    > Die Zahl ist hier 42 oder?
    Die Zahl ist: 42
    > nochmal hier 123
    Die Zahl ist: 123
    >
    

    zu erwähnen ist noch, dass 'hier' bzw. das Schlüsselwort auch als Wort gelesen werden können muss; d.h. hinter dem Schlüsselwort muss ein White Space Character (z.B.. Leerzeichen) stehen. Ein "hier100 ist die Zahl" oder "hier=100" würde nicht erkannt werden.

    Es gab schon mal einen sehr ausführlichen Thread zu dem Thema - finde ich aber eben nicht wieder ...

    Gruß
    Werner



  • @Werner

    exploit126 schrieb:

    Eine eigene Funktion kann ich selbst schreiben, aber ich dachte das es für so etwas zumindest in boost eine Lösung gibt.

    Es geht darum eine HTML Datei in verschiedene Bereiche einzteilen. Der Header endet mit "/n/r/n/r" und bis dahin will ich lesen.

    Und mit "HTML Datei" meint er höchstwahrscheinlich ne HTTP Response welche als Body ne HTML Seite mitschickt.
    Und anhand der Formulierung vermute ich dass er beide Teile, also auch den Teil vor dem "Wort" haben will.

    Klar kann das schief gehen wenn man furchtbar grosse Responses bekommt (die nicht in den Speicher passen). Oder wenn man es so massiv parallel macht dass die vielen kleineren Responses zusammen dann nicht in den Speicher passen.

    Meine Glaskugel sagt mir aber dass das für den OP kein Problem sein wird.


Anmelden zum Antworten