Menu

C++ String-Streams: Parsen und Erstellen mit stringstream

Wie man std::stringstream, istringstream und ostringstream verwendet, um Text zu parsen, Zeichenketten an Leerzeichen aufzuteilen, zwischen Zeichenketten und Zahlen zu konvertieren und formatierte Zeichenketten im Speicher zu erstellen.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Ein Stream, der in einer Zeichenkette lebt

Du kennst bereits cin und cout - Streams, die an Tastatur und Bildschirm angebunden sind. Ein String-Stream ist dieselbe Idee, nur dass die Daten stattdessen in einer std::string im Speicher leben. Du schreibst mit << hinein und ziehst Werte mit >> heraus, genau wie bei den Konsolen-Streams, aber nichts berührt das Terminal.

Diese eine Idee löst zwei alltägliche Probleme: Text in typisierte Werte zu parsen und aus gemischten Bausteinen eine formatierte Zeichenkette zu erstellen. Alles lebt im Header <sstream> und kommt in drei Varianten:

  • istringstream - nur lesend, zum Parsen von Eingaben.
  • ostringstream - nur schreibend, zum Erstellen von Ausgaben.
  • stringstream - in beide Richtungen.

ss.str() gibt alles bisher Geschriebene als einfache string zurück. Die <<-Operatoren haben dieselbe int-zu-Text-Formatierung vorgenommen wie cout - du hast das Ergebnis nur erfasst, anstatt es auszugeben.

Parsen: typisierte Werte herausziehen

Die wahre Stärke zeigt sich mit >>. Gib einem Stream etwas Text, und die Extraktion wandelt jedes Token in den von dir angeforderten Typ um, wobei Leerzeichen dazwischen übersprungen werden. So zerlegt man sauber eine Zeile in mehrere typisierte Felder:

Jedes >> liest bis zum nächsten Leerzeichen und konvertiert: "Ada" in eine string, "36" in ein int, "5.5" in ein double. Beachte hier das istringstream - der reine Eingabetyp macht deutlich, dass du nur parst.

Zeichenketten in Zahlen umwandeln (sicher)

Eine häufige Aufgabe ist es, eine einzelne Zeichenkette wie "42" in ein int zu verwandeln. Ein stringstream erledigt das und sagt dir, ob der Text tatsächlich eine gültige Zahl war - was atoi nie tut:

Hier liest ss >> value 123, hält beim a an und ist erfolgreich - validiere daher immer die gesamte Zeichenkette, wenn das wichtig ist. Eine robuste Prüfung besteht darin, die Zahl zu lesen und dann zu bestätigen, dass nichts Bedeutsames übrig bleibt. Für unkomplizierte Einzelwert-Umwandlungen sind std::stoi, std::stod und Verwandte (zusammen mit der Typumwandlung behandelt) kürzer; greife zu stringstream, wenn eine Zeichenkette mehrere gemischte Werte trägt.

Eine Zeichenkette an einem Trennzeichen aufteilen

Text aufzuteilen ist die am häufigsten gegoogelte String-Stream-Aufgabe. Kombiniere einen Stream mit std::getline, das bis zu jedem Trennzeichen lesen kann, nicht nur bis zu einem Zeilenumbruch:

Das Muster while (getline(...)) läuft in einer Schleife, bis der Stream leer ist, denn getline gibt den Stream zurück, und der Stream wird zu false ausgewertet, sobald nichts mehr übrig ist. Lässt du das dritte Argument weg, teilst du stattdessen mit >> an durch Leerzeichen getrennten Tokens auf - wähle das Trennzeichen, das deine Daten verwenden.

Zeichenketten im Speicher erstellen

In die andere Richtung setzt ostringstream eine formatierte Zeichenkette zusammen, ohne das Pufferüberlauf-Risiko von sprintf oder die fragile manuelle Verkettung. Es eignet sich perfekt für Logzeilen, Dateinamen oder Nachrichten, die aus Zahlen und Text zusammengesetzt sind:

Die gesamte <iomanip>-Formatierung, die du mit cout verwenden würdest - setw, setfill, setprecision, hex - funktioniert auf einem String-Stream identisch, sodass du aufgefüllte, festbreitige oder hexadezimale Ausgabe direkt in eine string erfasst bekommst.

Der Stolperstein: vor der Wiederverwendung zurücksetzen

Die Falle, in die jeder tappt, ist, einen Stream ohne Zurücksetzen wiederzuverwenden. Sobald ein Stream das Ende seiner Daten erreicht, rasten seine eof- und fail-Flags ein, und jedes spätere >> tut stillschweigend nichts - kein Fehler, nur veraltete Werte:

stringstream ss("10");
int a, b;
ss >> a;            // a = 10, Stream jetzt am Ende -> eof-Flag gesetzt
ss.str("20");       // neuen Text laden...
ss >> b;            // SCHLÄGT STILL FEHL - die Fehlerflags sind noch gesetzt, b bleibt unverändert

Du musst den Fehlerzustand und den Inhalt löschen. Die richtige Reihenfolge ist zuerst clear(), dann str():

Zwei verwandte Fehler: ss.clear() setzt die Flags zurück, leert aber den Puffer nicht (dafür ss.str("") verwenden), und ein stringstream, an den du fortlaufend mit << anhängst, wächst immer weiter - erstelle innerhalb einer Schleife einen frischen, statt für jede Iteration einen verschmutzten wiederzuverwenden.

Als Nächstes: Arrays

String-Streams haben dir eine saubere Möglichkeit gegeben, Text in typisierte Werte und wieder zurück zu verwandeln - oft eine ganze Liste davon, wie der vector, den du beim Aufteilen von CSV gefüllt hast. Um feste Sammlungen dieser Werte zu speichern und zu indizieren, brauchst du den grundlegendsten Container der Sprache. Als Nächstes behandeln wir Arrays: wie man sie deklariert, indiziert, über sie iteriert und den Zugriff außerhalb der Grenzen umgeht, der in C++ so viel undefiniertes Verhalten verursacht.

Häufig gestellte Fragen

Was ist ein stringstream in C++?

Ein std::stringstream ist ein Stream, der von einer string statt von der Tastatur oder einer Datei gespeist wird. Du schreibst mit << hinein und liest mit >> heraus, genau wie bei cout und cin, was ihn zum Standardwerkzeug zum Parsen von Text und zum Erstellen von Zeichenketten im Speicher macht. Er befindet sich im Header <sstream>.

Wie wandelt man in C++ mit stringstream eine Zeichenkette in ein int um?

Lege den Text in einen Stream und extrahiere ihn in eine Zahl: stringstream ss("42"); int n; ss >> n;. Prüfe mit if (ss) (oder if (ss >> n)), ob die Umwandlung tatsächlich erfolgreich war. Für einfache Fälle ist std::stoi kürzer, doch stringstream glänzt, wenn eine einzige Zeichenkette mehrere gemischte Werte enthält.

Warum muss ich clear() auf einem stringstream aufrufen?

Sobald ein Stream das Ende seiner Daten erreicht, bleiben seine eof/fail-Bits gesetzt, und jedes weitere >> tut stillschweigend nichts. Wenn du denselben stringstream mit neuem Inhalt wiederverwendest, rufe ss.clear() auf, um diese Fehlerflags zurückzusetzen, und dann ss.str(newText), um frische Daten zu laden - sonst schlagen die Lesevorgänge stillschweigend fehl.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S