Para crear un stream de cadena de salida, simplemente cree un objeto ostringstream, que maneja un buffer de carácteres dinamicamente dimensionado para guardar cualquier cosas que usted inserte. Para tomar el resultado formateado como un objeto de string, llame a la función miembro setr(). Aqui tiene un ejemplo:
//: C04:Ostring.cpp {RunByHand} // Illustrates ostringstream. #include <iostream> #include <sstream> #include <string> using namespace std; int main() { cout << "type an int, a float and a string: "; int i; float f; cin >> i >> f; cin >> ws; // Throw away white space string stuff; getline(cin, stuff); // Get rest of the line ostringstream os; os << "integer = " << i << endl; os << "float = " << f << endl; os << "string = " << stuff << endl; string result = os.str(); cout << result << endl; } ///:~
Listado 5.12. C04/Ostring.cpp
Esto es similar al ejemplo Istring.cpp anterior que pedía un
int
y un float
. A continueación una
simple ejecución (la entrada por teclado está escrita en
negrita).
type an int, a float and a string: FIXME:10 20.5 the end integer = 10 float = 20.5 string = the end
Puede ver que, como otros stream
de
salida, puede usar las herramientas ordinarias de formateo,
como el operador << y endl
, para
enviar bytes hacia el ostringstream
. La
función str()
devuelve un nuevo objeto
string
cada vez que usted la llama con
lo que el stringbuf
contenido permanece
inalterado.
En el capítulo previo, presentamos un programa,
HTMLStripper.cpp, que borraba todas las etiqietas HTML y los
códigos especiales de un fichero de texto. Como prometíamos,
aqui está una versión más elegante usando
streams
de cadena.
//: C04:HTMLStripper2.cpp {RunByHand} //{L} ../C03/ReplaceAll // Filter to remove html tags and markers. #include <cstddef> #include <cstdlib> #include <fstream> #include <iostream> #include <sstream> #include <stdexcept> #include <string> #include "../C03/ReplaceAll.h" #include "../require.h" using namespace std; string& stripHTMLTags(string& s) throw(runtime_error) { size_t leftPos; while((leftPos = s.find('<')) != string::npos) { size_t rightPos = s.find('>', leftPos+1); if(rightPos == string::npos) { ostringstream msg; msg << "Incomplete HTML tag starting in position " << leftPos; throw runtime_error(msg.str()); } s.erase(leftPos, rightPos - leftPos + 1); } // Remove all special HTML characters replaceAll(s, "<", "<"); replaceAll(s, ">", ">"); replaceAll(s, "&", "&"); replaceAll(s, " ", " "); // Etc... return s; } int main(int argc, char* argv[]) { requireArgs(argc, 1, "usage: HTMLStripper2 InputFile"); ifstream in(argv[1]); assure(in, argv[1]); // Read entire file into string; then strip ostringstream ss; ss << in.rdbuf(); try { string s = ss.str(); cout << stripHTMLTags(s) << endl; return EXIT_SUCCESS; } catch(runtime_error& x) { cout << x.what() << endl; return EXIT_FAILURE; } } ///:~
Listado 5.13. C04/HTMLStripper2.cpp
En este programa leemos el fichero entero dentro de un string
insertando una llamada rdbuf()
del stream
de fichero al ostringstream
. Ahora es fácil buscar parejas de delimitadores HTML
y borrarlas sin tener que preocuparnos de límites de líneas como teniamos con la versión previa en el Capítulo 3.
El siguiente ejemplo muestra como usar un stream de cadena bidireccional (esto es, lectura/escritura):
//: C04:StringSeeking.cpp {-bor}{-dmc} // Reads and writes a string stream. #include <cassert> #include <sstream> #include <string> using namespace std; int main() { string text = "We will hook no fish"; stringstream ss(text); ss.seekp(0, ios::end); ss << " before its time."; assert(ss.str() == "We will hook no fish before its time."); // Change "hook" to "ship" ss.seekg(8, ios::beg); string word; ss >> word; assert(word == "hook"); ss.seekp(8, ios::beg); ss << "ship"; // Change "fish" to "code" ss.seekg(16, ios::beg); ss >> word; assert(word == "fish"); ss.seekp(16, ios::beg); ss << "code"; assert(ss.str() == "We will ship no code before its time."); ss.str("A horse of a different color."); assert(ss.str() == "A horse of a different color."); } ///:~
Listado 5.14. C04/StringSeeking.cpp
Como siempre para mover el puntero de inserción, usted llama a
seekp()
, y para reposicionar el fichero
de lectura, usted llama a
seekg()
. Incluso aunque no lo hemos
mostrado con este ejemplo, los stream
de cadeana son un poco más permisivos que los
stream
de fichero ya que podemos
cambiar de lectura a escritura y viceversa en cualquier
momento. No necesita reposicionar el puntero de lectura o de
escritura o vaciar el stream
. Este
progrma también ilustra la sobrecarga de
str()
que reemplaza el
stringbuf
contenido en el
stream
con una nueva cadena.