Un stream
de cadena funciona directamente en memoria en vez de con ficheros o la salida
estándar. Usa las mismas funciones de lectura y formateo que usó con cin
y
cout
para manipular bits en memoria. En ordenadores antiguos, la memoria se refería al
núcleo, con lo que este tipo de funcionalidad se llama a menudo formateo en el núcleo.
Los nombres de clases para streams
de cadena son una copia de los streams
de
ficheros. Si usted quiere crear un stream
de cadena para extraer carácteres de él, puede crear un
istringstream
. Si quiere poner carácteres en un stream
de cadena, puede crear
un ostringstream
. Todas las declaraciones para streams
de cadena están en la
cabecera estándar <sstream>. Como es habitual, hay plantillas de clases dentro de la jerarquia de los
iostreams
, como se muestra en la siguiente figura:
Para leer de un string
usando
operaciones de stream
, cree un objeto
istringstream
inicializado con el
string
. El siguiente programa muestra
como usar un objeto istringstream
:
//: C04:Istring.cpp // Input string streams. #include <cassert> #include <cmath> // For fabs() #include <iostream> #include <limits> // For epsilon() #include <sstream> #include <string> using namespace std; int main() { istringstream s("47 1.414 This is a test"); int i; double f; s >> i >> f; // Whitespace-delimited input assert(i == 47); double relerr = (fabs(f) - 1.414) / 1.414; assert(relerr <= numeric_limits<double>::epsilon()); string buf2; s >> buf2; assert(buf2 == "This"); cout << s.rdbuf(); // " is a test" } ///:~
Listado 5.10. C04/Istring.cpp
Puede ver que es un acercamiento más flexible y general para
transformar cadenas de carácteres para valores con tipo que la
librería de funciones del estándar de C, como
atof()
o atoi()
,
aunque esta última puede ser más eficaz para las conversiones
individuales.
En la expresión s >> i >> f
, el
primer número se extrae en i
, y en el
segundo en f
. Este no es 'el primer
conjunto de carácteres delimitado por espacios en blanco' por
que depende del tipo de datos que está siendo extraído. Por
ejemplo, si la cadena fuera '1.414 47 This is a test',
entonces i
tomaría el valor 1 porque la
rutina de entrada se pararía en el punto decimal. Entonces
f
tomaría 0.414. Esto puede ser muy útil i
si quiere partir un número de coma flotante entre la parte
entera y la decimal. De otra manera parecería un error. El
segundo assert()
calcula el error
relativo entre lo que leemos y lo que esperamos; siempre es
mejor hacer esto que comparar la igualdad de números de coma
flotante. La constante devuelta por
epsilon()
, definida en <limits>,
representa la epsilon de la máquina para números de doble
precisión, el cual es la mejor tolerancia que se puede esperar
para satisfacer las comparaciones de double.[16].
Como debe haber supuesto, buf2
no toma el
resto del string
, simplemente la
siguiente palabra delimitada por espacios en blanco. En
general, el mejor usar el extractor en
iostreams
cuando usted conoce
exactamente la secuencia de datos en el
stream
de entrada y los convierte a
algún otro tipo que un string
de
carácteres. No obstante, si quiere extraer el resto del
string
de una sola vez y enviarlo a
otro iostream
, puede usar
rdbuf()
como se muestra.
Para probar el extractor de Date
al
principio de este capítulo, hemos usado un
stream
de cadena de entrada con el
siguiente programa de prueba:
//: C04:DateIOTest.cpp //{L} ../C02/Date #include <iostream> #include <sstream> #include "../C02/Date.h" using namespace std; void testDate(const string& s) { istringstream os(s); Date d; os >> d; if(os) cout << d << endl; else cout << "input error with \"" << s << "\"" << endl; } int main() { testDate("08-10-2003"); testDate("8-10-2003"); testDate("08 - 10 - 2003"); testDate("A-10-2003"); testDate("08%10/2003"); } ///:~
Listado 5.11. C04/DateIOTest.cpp
Cada literal de cadena en main()
se pasa
por referencia a testDate()
, que a su vez
lo envuelve en un istringstream
con lo
que podemos probar el extractor de
stream
que escribimos para los objetos
Date
. La función
testDate()
también empieza por probar el
insertador, operator<<()
.
[16] Para más información sobre la epsilon de la máquina y el cómputo de punto flotante en general, vea el artículo de Chuck, "The Standard C Library, Part 3", C/C++ Users Journal, Marzo 1995, disponible en www.freshsources.com/1995006a.htm