getline - string einlesen



  • So, erste Version a la Hacker:

    istream& mgetline(istream&, string&, char = '\n', size_t = 500);
    istream& mgetline(istream& toread, string& tofill, char delim, size_t max)
    {
            char array[max];
            toread.read(array, max);
            *(strchr(array, delim)) = 0;
            tofill = array;
            return toread;
    }
    

  • Mod

    Ist das so eine Art Wettbewerb wie es immer schlechter geht? Da war ja die Simpelvorgabe von redrew99 noch besser. Die hat zumindest ohne Einschränkungen und noch dazu ohne Compilererweiterungen funktioniert.



  • redrew99 schrieb:

    Also wenn eine Zeile zeichenweise ausgelesen und in den String übertragen wurde, ist der String ja nicht mehr leer, wenn man nun eine zweite Zeile ausliest und in den String überträgt, wird sie doch normalerweise hintenangehängt.

    Wie kommst Du darauf?

    Ich würde jetzt "logisch" annehmen, wenn man eine zweite Zeile ausliest und in den String überträgt, dass dann die zweite Zeile im String steht und nicht beide.



  • LordJaxom schrieb:

    Wie kommst Du darauf?

    Ich würde jetzt "logisch" annehmen, wenn man eine zweite Zeile ausliest und in den String überträgt, dass dann die zweite Zeile im String steht und nicht beide.

    Naja, bei folgendem Programm ist das nicht so, wenn in Zeile 9 der String nicht geleert wird:

    #include <iostream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    void my_getline(istream &filestream,string &s)
    {
       //s="";   
       for (char ch;&filestream.get(ch);)
         {
           if(ch!='\n')
           {
               s+=ch;
           }
           else //if (ch=='\n')
           {
             break;
           }
         }
    }
    
    int main()
    {
        ifstream filestream("test.txt");
        for(string s;filestream.good();)
        {
          my_getline(filestream,s);
          cout<<s<<endl;
        }
    return 0;
    }
    


  • SeppJ schrieb:

    Ist das so eine Art Wettbewerb wie es immer schlechter geht? Da war ja die Simpelvorgabe von redrew99 noch besser. Die hat zumindest ohne Einschränkungen und noch dazu ohne Compilererweiterungen funktioniert.

    Ja, du hast Recht - Schwachsinn. Merke jetzt auch, dass meine Funktion überhaupt nicht Funktioniert; auf Ideone hat sie das nähmlich (teilweise).



  • SeppJ schrieb:

    Ich meine: Schreibe eine Funktion std::ostream& my_getline(std::ostream &in, std::string &result) , die eine Zeile aus in liest, in result speichert und den Rest von in zurück gibt.

    Ich habe da noch eine Idee, man liest den Stream bis zum nächsten Zeilenumbruch aus und gibt dann einen Zeiger auf das nächste Zeichen zurück.

    Was mir gerade einfällt, evtl. kann man das auch mit streamiteratoren umsetzen.



  • std::istream& getline(std::istream& in, std::string& out, char delim)
    {
        out.clear();
        for(int c = in.get(); in; c = in.get()) 
        {
            if(c != delim)
                out += c;
            else
                break;
        }
    
        return in;
    }
    

    So isses korrekt nach Standard.



  • Nö, eof wird zu früh gesetzt, sodass bei einem while(getline(...)) die letzte Zeile nicht mehr verarbeitet wird.



  • Kann ich nicht reproduzieren.


  • Mod

    Ethon schrieb:

    Kann ich nicht reproduzieren.

    Versuch mal eine Datei, deren letzte Zeile nicht auf einem Newline endet. Oder probier einen anderen Delimiter. Apropos, sollte dieser als Defaultwert ein Newline haben.



  • Stimmt, man könnte aber im Vorfeld prüfen, ob das letzte Zeichen ein Zeilenumbruch ist, falls nicht, fügt man halt eins ein.

    Oder man prüft einfach nur, ob das Ende der Datei erreicht ist.
    Falls ja, wird der String doch noch ausgegeben bzw. die Zeichen der letzten Zeile dort gespeichert.

    Bin dann off für heute.



  • kann man das eigtl eleganter implementieren? gefällt mir nicht so recht.

    std::istream& getline(std::istream& in, std::string& out, char delim = '\n')
    {
      out.clear();
    
      {
        char to_add;
        while(in.get(to_add))
        {
          if(to_add == delim)
            return in;
    
          out.push_back(to_add);
        };
      }
    
      return in;
    }
    

    bb



  • Du hast denselben Bug wie Ethon. Ich denke, dass du beim ersten Erreichen von eof das Flag wieder zurücksetzen musst.



  • richtig - nachdenken 4tw -.-'
    wollts eigtl noch testen, aber da hat mir dann doch iwie die lust gefehlt 😃

    std::istream& getline(std::istream& in, std::string& out, char delim = '\n')
    {
      out.clear();
    
      if(!in.eof())
      {
        char to_add;
        while(in.get(to_add))
        {
          if(to_add == delim)
            return in;
    
          out.push_back(to_add);
        };
    
        in.setstate(in.rdstat() & ~std::ios::eof);
      }
    
      return in;
    }
    


  • Ethons Code funktioniert, auch wenn man am Ende einer Datei den Zeilenumbruch entfernt.
    Allerdings verstehe ich nicht, was

    for(int c = in.get(); in; c = in.get())
    

    da genau passiert. Mir ist klar, daß der Stream gelesen wird, aber nicht, wie.
    Was bedeutet

    int c=in.get();
    

    ?
    und müßte man nicht schreiben

    in.good()
    

    statt

    in
    

    ?



  • redrew99 schrieb:

    Was bedeutet int c=in.get(); ? [...]

    in.get() gibt ein Zeichen aus dem Stream zurück.

    redrew99 schrieb:

    [...] und müßte man nicht schreiben in.good() statt in ?

    Nein, müsste man nicht. Das Prüfen auf failbit und badbit erledigt der "Convert-to-Pointer"-Operator ( operator void *() ) aus ios .



  • SeppJ schrieb:

    Ist das so eine Art Wettbewerb wie es immer schlechter geht?

    Keine Ahnung. Aber wenn's so ist, dann darf ich wenigstens auch mitmachen 😉



  • redrew99 schrieb:

    Ethons Code funktioniert, auch wenn man am Ende einer Datei den Zeilenumbruch entfernt.

    Das kann ich mir ehrlich gesagt nicht vorstellen. Wird dann auch die letzte Zeile verarbeitet bei folgendem Code?

    string line;
    while(getline(in, line))
        cout << line << endl;
    


  • Nope. Einerseits könnte man argumentieren dass eine Zeile ohne Zeilenende kein gültiges Token ist. Andererseits ist das in der Praxis Mist. 😉



  • Also dieser Code (die Funktion ist von Ethan) funktioniert:

    #include <iostream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    std::istream& getline(std::istream& in, std::string& out, char delim)
    {
        out.clear();
        for(int c = in.get(); in; c = in.get())
    
        {
            if(c != delim)
                out += c;
            else
                break;
        }
    
        return in;
    }
    
    int main()
    {
        string s;
        ifstream filestream("test.txt");
        for(;filestream.good();)
        {
          getline(filestream,s,'\n');
          cout<<s<<endl;
        }
        return 0;
    }
    

Anmelden zum Antworten