Zeilenumbruch aus String durch ein Zeichen ersetzen



  • Ich möchte gerne aus einem String s, z.B.
    345
    67
    8
    9
    die Zeilenumbrüche durch ein anderes Zeichen ersetzen, leider funktioniert das nicht so wie gewünscht.
    Z.B.

    for(int unsigned i=0;i<s.size();++i)
    {
     if(s[i]=='\n')    // oder if(s[i]=='\r\n'), bin mir nicht ganz sicher, was richtig ist.
     {
      s[i]='-';
     }
    }
    

    Alternativ hatte ich mir überlegt, string::replace() einzusetzen, aber auf http://www.cplusplus.com/reference/string/string/replace/ sind nur Beispiele, wie man Positionen ersetzen kann, aber nicht
    bestimmte Zeichen.



  • Was wäre das Ergebnis?



  • Also so klappts:

    #include <iostream>
    #include <string>
    
    int main()
    {
        std::string s = "5\n4\n123\n";
        for(auto iter = s.begin(); iter != s.end(); ++iter)
            if(*iter == '\n')
                *iter = 'x';
        std::cout << s; //5x4x123x
    }
    


  • http://www.cplusplus.com/reference/algorithm/replace/

    int main ()
    {
    	string foo = "345\n67\n8\n9";
    	replace(foo.begin(), foo.end(), '\n', ' ');
    	cout << foo << endl;
    	return 0;
    }
    


  • Die erinnerung schrieb:

    Was wäre das Ergebnis?

    Datensalat: "-9" und zwei Sonderzeichen.
    Deine Frage hat mich auf die Idee gebracht, den Code einfach mal so auszuprobieren. Also einfach einen
    String erzeugt und mit einem Wert versehen und dann die Schleife hinterher, funktioniert einwandfrei, der Code
    ist also richtig gewesen.
    Die gepostete Schleife war nur Teil eines Programms, welches im Vorfeld eine Datei ausliest und den Inhalt
    in ein CharArray umwandelt, welches anschließend in einen String übertragen wird. Mir ist bewußt, daß man das auch anders programmieren kann, was ich eben auch mal getan habe, auch das funktioniert einwandfrei.
    Ich hatte den Codeteil nur aus Bequemlichkeit übernommen, müßte so aber auch funktionieren normalerweise.

    #include <iostream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    int main()
    {
     int length;
     ifstream filestream("test.txt",ios::binary);
     filestream.seekg(0,ios::end);
     length=filestream.tellg();
     filestream.seekg(0,ios::beg);
     char buffer[length];
     filestream.read(buffer,length);
     //filestream.close();
     string s=buffer;
     for(unsigned int i=0;i<s.size();++i)
     {
         if (s[i]=='\n')  //oder if (s[i]=='\r\n')
         {
             s[i]='-';
         }
     }
    cout<<s;
    return 0;
    }
    


  • gelöscht



  • Wurstinator schrieb:

    http://www.cplusplus.com/reference/algorithm/replace/

    int main ()
    {
    	string foo = "345\n67\n8\n9";
    	replace(foo.begin(), foo.end(), '\n', ' ');
    	cout << foo << endl;
    	return 0;
    }
    

    Incocnito schrieb:

    Also so klappts:

    #include <iostream>
    #include <string>
    
    int main()
    {
        std::string s = "5\n4\n123\n";
        for(auto iter = s.begin(); iter != s.end(); ++iter)
            if(*iter == '\n')
                *iter = 'x';
        std::cout << s; //5x4x123x
    }
    

    Thx, so geht es mit Iteratoren.



  • Soll dein Code irgendwie das hier machen?

    #include <iostream>
    #include <fstream>
    #include <string>
    
    int main()
    {
        std::ifstream datei("datei.dat");
        char c;
        std::string s;
        while(datei.get(c))
            if(c == '\n')
                s.push_back('-');
            else
                s.push_back(c);
        std::cout << s;
    }
    


  • buffer ist nicht nullterminiert; dementsprechend erzeugt

    string s=buffer;
    

    undefiniertes Verhalten, und danach ist alles reine Glückssache.

    Versuch's mal mit

    string s(buffer, buffer + length);
    

    Ansonsten geht das auch einfacher mit Stringstreams:

    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    
    int main() {
      std::ifstream file("test.txt");
      std::ostringstream buffer;
    
      buffer << file.rdbuf();
      std::string s = buffer.str();
    
      std::replace(s.begin(), s.end(), '\n', '-');
      std::cout << s;
    }
    


  • seldon schrieb:

    Ansonsten geht das auch einfacher mit Stringstreams:

    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    
    int main() {
      std::ifstream file("test.txt");
      std::ostringstream buffer;
    
      buffer << file.rdbuf();
      std::string s = buffer.str();
    
      std::replace(s.begin(), s.end(), '\n', '-');
      std::cout << s;
    }
    

    Ja, thx.

    seldon schrieb:

    buffer ist nicht nullterminiert; dementsprechend erzeugt

    string s=buffer;
    

    undefiniertes Verhalten, und danach ist alles reine Glückssache.

    Ok, dann müßte man doch einfach das Array um ein Element größer erzeugen und an die letzte Stelle
    die Nullterminierung einfügen können.

    char buffer[length+1];
    ...
    buffer[length+1]='\0';
    

    seldon schrieb:

    Versuch's mal mit

    string s(buffer, buffer + length);
    

    Sry, das funktioniert leider nicht.



  • Was steht denn in der Datei drin, und was kriegst du mit nullterminiertem Buffer als Ausgabe?

    Das einzige, was mir so spontan noch auffällt, ist das ios::binary beim Öffnen der Datei. Wenn du unter Windows arbeitest, könntest du auf die Art Strings der Form "Zeile1\r-Zeile2\r-Zeile3\r-" bekommen, und da \r ein Steuerzeichen (gehe zum Anfang der Zeile) ist, dürfte das auf der Konsole komisch aussehen (in diesem Fall "-eile3" mit dem Cursor auf dem ersten 'e').



  • Also mit Nullterminiertem Array sieht der Code dann so aus:

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <string.h>
    
    using namespace std;
    
    int main()
    {
     int length;
     ifstream filestream("test.txt",ios::binary);
     filestream.seekg(0,ios::end);
     length=filestream.tellg();
     filestream.seekg(0,ios::beg);
     char buffer[length+1];
     filestream.read(buffer,length);
     buffer[length+1]='\0';
     string s=buffer;
     for(unsigned int i=0;i<s.size();++i)
     {
         if (s[i]=='\r\n')                // ohne '\r' ist die Ausgabe nur Datensalat.
         {
             s[i]='-';
         }
     }
    cout<<s;
    }
    

    Ausgabe erfolgt mit einem Sonderzeichen am Ende, das wird dann wohl das '\0' sein.
    Allerdings werden die Zeilenumbrüche nicht entfernt.
    Interessant ist, daß wenn man man die If-Abfrage nur mit "\r" schreibt, das dann am Ende jeder
    Zeile das "\r" durch "-" ersetzt wird. Die Zeilenumbrüche bleiben aber trotzdem bestehen.
    Schätze aber auch, daß das mit ios::binary zu tun hat. Irgendwie werden da die Steuerzeichen "vermurkst".



  • ohne den rest angeguckt zu haben:

    char buffer[length+1]; //kein standard c++ - nimm std::vector
     filestream.read(buffer,length); 
     buffer[length+1]='\0'; // !!!   buffer[length] - dann hättest du im debug-mode hier auch nen assert gehabt...
    

    bb



  • Statt

    ifstream filestream("test.txt",ios::binary);
    

    schreib mal

    ifstream filestream("test.txt");
    

    Unter Windows werden Textdateien so behandelt, dass Zeilenenden durch "\r\n" dargestellt werden (also zwei Zeichen). Wenn du die Datei im Textmodus öffnest, übernimmt das System die Umwandlung für dich, mit ios::binary kriegst du den Kram halt in Rohfassung und müsstest das \r selbst ignorieren. \r bedeutet "geh wieder zum Anfang der Zeile zurück", und das führt natürlich zu seltsamer Ausgabe, wenn man es einfach drinlässt.



  • Ja, das funktioniert. Danke für die direkte Info.
    Du hast absolut Recht, in binärer Form werden alle Zeichen, also auch diverse
    Steuerzeichen mit übertragen, allerdings nicht nur '\r\n', denn sonst könnte man die einfach mit

    remove (s.begin(), s.end(), '\n');
     replace (s.begin(), s.end(), '\r','-');
    

    entfernen. Was aber nicht funktioniert, es werden immer noch 2 Sonderzeichen mit
    ausgegeben 🙂
    Ich habe mir deshalb mal den Spass gemacht, die Zeichen des Strings mit

    int zahl;
    for(unsigned i=0;i<s.size();++i)
    {
        zahl=s[i];
        cout<<zahl<<endl;
    }
    

    einzeln als ASCII-Zeichen ausgeben zu lassen. Das Ergebnis sind 15 Zeichen(!),
    7 sind Zahlen, 6 sind '\r\n', bleiben also 2 übrig. Eines davon könnte
    die Nullterminierung sein, aber das andere?
    Sind übrigens ASII: 21 und 64.



  • Meintest du

    s.erase(remove(s.begin(), s.end(), '\n'), s.end());
    

    ?



  • Ja, das geht natürlich auch.
    Allerdings verbleiben auch da 2 Zeichen im String.


Anmelden zum Antworten