La función insert()
es particularmente
útil por que te evita el tener que estar seguro de que la
inserción de caracteres en un string
no
sobrepasa el espacio reservado o sobrescribe los caracteres
que inmediatamente siguientes al punto de inserción. El
espacio crece y los caracteres existentes se mueven
graciosamente para acomodar a los nuevos elementos. A veces,
puede que no sea esto exactamente lo que quiere. Si quiere que
el tamaño del string
permanezca sin
cambios, use la función replace()
para
sobrescribir los caracteres. Existe un número de versiones
sobrecargadas de replace()
, pero la más
simple toma tres argumentos: un entero indicando donde empezar
en el string
, un entero indicando
cuantos caracteres para eliminar del
string
original, y el
string
con el que reemplazaremos (que
puede ser diferente en numero de caracteres que la cantidad
eliminada). Aquí un ejemplo simple:
//: C03:StringReplace.cpp // Simple find-and-replace in strings. #include <cassert> #include <string> using namespace std; int main() { string s("A piece of text"); string tag("$tag$"); s.insert(8, tag + ' '); assert(s == "A piece $tag$ of text"); int start = s.find(tag); assert(start == 8); assert(tag.size() == 5); s.replace(start, tag.size(), "hello there"); assert(s == "A piece hello there of text"); } ///:~
Listado 4.3. C03/StringReplace.cpp
Tag
es insertada en s
(notese que la inserción ocurre antes de
que el valor indicando el punto de inserción y de que el
espacio extra haya sido añadido despues de
Tag
), y entonces es encontrada y
reemplazada.
Debería cerciorarse de que ha encontrado algo antes de
realizar el replace()
. En los ejemplos
anteriores se reemplaza con un char*
, pero existe
una versión sobrecargada que reemplaza con un
string
. Aqui hay un ejempl más completo
de demostración de replace()
:
//: C03:Replace.cpp #include <cassert> #include <cstddef> // For size_t #include <string> using namespace std; void replaceChars(string& modifyMe, const string& findMe, const string& newChars) { // Look in modifyMe for the "find string" // starting at position 0: size_t i = modifyMe.find(findMe, 0); // Did we find the string to replace? if(i != string::npos) // Replace the find string with newChars: modifyMe.replace(i, findMe.size(), newChars); } int main() { string bigNews = "I thought I saw Elvis in a UFO. " "I have been working too hard."; string replacement("wig"); string findMe("UFO"); // Find "UFO" in bigNews and overwrite it: replaceChars(bigNews, findMe, replacement); assert(bigNews == "I thought I saw Elvis in a " "wig. I have been working too hard."); } ///:~
Listado 4.4. C03/Replace.cpp
Si replace()
no encuentra la cadena
buscada, retorna un
string::
npos
. El
dato miembro npos
es una constante estatica
de la clase string
que representa una
posición de carácter que no existe[33].
[3]
A diferencia de insert()
,
replace()
no aumentará el espacio de
alamcenamiento de string
si copia
nuevos caracteres en el medio de una serie de elementos de
array existentes. Sin embargo, sí que cerecerá su espacio si
es necesario, por ejemplo, cuando hace un
"reemplazamiento" que pueda expandir el
string
más allá del final de la memoria
reservada actual. Aquí un ejemplo:
//: C03:ReplaceAndGrow.cpp #include <cassert> #include <string> using namespace std; int main() { string bigNews("I have been working the grave."); string replacement("yard shift."); // The first argument says "replace chars // beyond the end of the existing string": bigNews.replace(bigNews.size() - 1, replacement.size(), replacement); assert(bigNews == "I have been working the " "graveyard shift."); } ///:~
Listado 4.5. C03/ReplaceAndGrow.cpp
La llamada a replace()
empieza
"reemplazando" más allá del final del
array existente, que es equivalente a la operación
append()
. Nótese que en este ejemplo
replace()
expande el array
coherentemente.
Puede que haya estado buscando a través del capítulo;
intentando hacer algo relativamente fácil como reemplazar
todas las ocurrencias de un carácter con diferentes
caracteres. Al buscar el material previo sobre reemplazar,
puede que haya encontrado la respuesta, pero entonces ha
empezaro viendo grupos de caracteres y contadores y otras
cosas que parecen un poco demasiado complejas. ¿No tiene
string
una manera para reemplazar un
carácter con otro simplemente?
Puede escribir fácilmente cada funcin usando las funciones
miembro find()
y
replace()
como se muestra acontinuacion.
//: C03:ReplaceAll.h #ifndef REPLACEALL_H #define REPLACEALL_H #include <string> std::string& replaceAll(std::string& context, const std::string& from, const std::string& to); #endif // REPLACEALL_H ///:~
Listado 4.6. C03/ReplaceAll.h
//: C03:ReplaceAll.cpp {O} #include <cstddef> #include "ReplaceAll.h" using namespace std; string& replaceAll(string& context, const string& from, const string& to) { size_t lookHere = 0; size_t foundHere; while((foundHere = context.find(from, lookHere)) != string::npos) { context.replace(foundHere, from.size(), to); lookHere = foundHere + to.size(); } return context; } ///:~
Listado 4.7. C03/ReplaceAll.cpp
La versión de find()
usada aquí toma como
segundo argumento la posición donde empezar a buscar y retorna
string::
npos
si no
lo encuentra. Es importante avanzar en la posición contenida
por la variable lookHere
pasada como
subcadena, en caso de que from
es una
subcadena de to
. El siguiente programa
comprueba la funcion replaceAll()
:
//: C03:ReplaceAllTest.cpp //{L} ReplaceAll #include <cassert> #include <iostream> #include <string> #include "ReplaceAll.h" using namespace std; int main() { string text = "a man, a plan, a canal, Panama"; replaceAll(text, "an", "XXX"); assert(text == "a mXXX, a plXXX, a cXXXal, PXXXama"); } ///:~
Listado 4.8. C03/ReplaceAllTest.cpp
Como puede comprobar, la clase string
por ella sola no resuelve todos los posibles problemas. Muchas
soluciones se han dejado en los algoritmos de la librería
estándar[4] por que la clase
string
puede parece justamente como una
secuencia STL(gracias a los iteradores descritos antes). Todos
los algoritmos genéricos funcionan en un
"rango" de elementos dentro de un
contenedor. Generalmente este rango es justamente desde el
principio del contenedor hasta el final. Un objeto
string
se parece a un contenedor de
caracteres: para obtener el principio de este rango use
string::
begin()
, y
para obtener el final del rango use
string::
end()
. El
siguiente ejemplomuestra el uso del algoritmo
replace()
para reemplazar todas las
instancias de un determinado carácter "X"
con "Y"
//: C03:StringCharReplace.cpp #include <algorithm> #include <cassert> #include <string> using namespace std; int main() { string s("aaaXaaaXXaaXXXaXXXXaaa"); replace(s.begin(), s.end(), 'X', 'Y'); assert(s == "aaaYaaaYYaaYYYaYYYYaaa"); } ///:~
Listado 4.9. C03/StringCharReplace.cpp
Nótese que esta función replace()
no es
llamada como función miembro de
string
. Además, a diferencia de la
función
string::
replace()
,
que solo realiza un reemplazo, el algoritmo
replace()
reemplaza todas las instancias
de un carácter con otro.
El algoritmo replace()
solo funciona con
objetos individuales (en este caso, objetos char
)
y no reemplazará arreglos constantes o objetos
string
. Desde que un
string
se copmporta como una secuencia
STL, un conjunto de algoritmos pueden serle aplicados, que
resolverán otros problemas que las funciones miembro de
string
no resuelven.