Estás jugando un poco con la memoria aquí con todas las llamadas a "reemplazar": la complejidad sería n² si eliminas "o" de "ooooooo ... o". Supongo que se puede hacer mejor, pero esta solución tiene el mérito de ser fácil de entender.
Zonko
1
¿Por qué no es un bucle for real, en lugar de un bucle for ofuscado?
Shirik
Estoy acostumbrado a aplicar el principio de "mínima sorpresa". Los bucles for son para uso simple de incremento de índice, la mayor parte del tiempo. Aquí, según yo, un bucle de tiempo es más claro.
yves Baumes
1
@aldo Como regla general, es mejor evitar la complejidad y, por ejemplo, usar expresiones regulares como se menciona en otras respuestas. Pero dependiendo de su necesidad, es posible que desee controlar las dependencias de su proyecto. Un pequeño fragmento de código que hace exactamente lo que necesita, no más, a veces es mejor.
yves Baumes
158
#include<boost/algorithm/string.hpp>// include Boost, a C++ library...
std::string target("Would you like a foo of chocolate. Two foos of chocolate?");
boost::replace_all(target,"foo","bar");
Tenga en cuenta que no tiene que crear explícitamente std :: string's para el patrón y el reemplazo: boost :: replace_all (target, "foo", "bar");
Alexis Wilke
4
+1, con una advertencia: replace_allse producirá un error de segmentación para las versiones de boost> 1.43 en Sun Studio para cualquier versión <12.3
Brian Vandenberg
3
boostaumenta considerablemente el tiempo de compilación en dispositivos integrados. Incluso ARMv7 de cuatro núcleos. Se compilan 100 líneas de código en 2 minutos, sin impulso, 2 segundos.
Piotr Kula
4
@ppumkin: eso significa que su compilador (o configuración de compilación, o lo que sea) apesta, no la arquitectura de destino, que no tiene nada que ver con eso.
Daniel Kamil Kozar
Si su compilador admite un encabezado precompilado, se recomienda encarecidamente usarlo cuando use boost. Realmente ahorra tiempo.
Alexey Omelchenko
33
En C ++ 11, puede hacer esto como una línea con una llamada a regex_replace:
#include<string>#include<regex>using std::string;
string do_replace( string const& in, string const& from, string const& to ){return std::regex_replace( in, std::regex(from), to );}
string test ="Remove all spaces";
std::cout << do_replace(test," ","")<< std::endl;
Tenga en cuenta también que frompuede ser una expresión regular, por lo que puede utilizar criterios de coincidencia más sofisticados si es necesario. Lo que no veo es cómo hacer esto sin aplicar alguna forma de análisis de expresiones regulares, en lugar de usar solo una interpretación directa de los fromcaracteres.
Brent Bradburn
Esto puede requerir un compilador actualizado. Funcionó con gcc 5.0, pero tuve algunos problemas con gcc 4.8.4.
Brent Bradburn
@nobar, sí, si recuerdo bien, el soporte de expresiones regulares en 4.8.x no estaba completo. También puede tener búsquedas más sofisticadas, pero se penaliza el tiempo ... Será más lento que las otras funciones de búsqueda y reemplazo más sencillas.
Alexis Wilke
2
Tenga en cuenta que esto solo funcionará para caracteres alfanuméricos muy básicos y nada más sin hacer mucho preprocesamiento según el tipo de cadena. Todavía no he encontrado un reemplazo de cadena basado en expresiones regulares de propósito general.
Probé esta muestra en GCC pero no se compilaba; no le gustó el uso de T :: size_t. Reemplazar T :: size_t con typename T :: size_type soluciona el problema.
Andrew Wyatt
3
La forma más fácil (ofreciendo algo parecido a lo que escribió) es usar Boost.Regex , específicamente regex_replace .
std :: string tiene incorporados los métodos find () y replace (), pero es más complicado trabajar con ellos ya que requieren lidiar con índices y longitudes de cadenas.
También están los algoritmos de cadena de refuerzo, incluido replace_all (la expresión regular puede ser un poco pesada para una sustitución tan simple).
UncleBens
3
Creo que esto funcionaría. Toma const char * como parámetro.
//params find and replace cannot be NULLvoidFindAndReplace( std::string& source,constchar* find,constchar* replace ){//ASSERT(find != NULL);//ASSERT(replace != NULL);size_t findLen = strlen(find);size_t replaceLen = strlen(replace);size_t pos =0;//search for the next occurrence of find within sourcewhile((pos = source.find(find, pos))!= std::string::npos){//replace the found string with the replacement
source.replace( pos, findLen, replace );//the next line keeps you from searching your replace string, //so your could replace "hello" with "hello world" //and not have it blow chunks.
pos += replaceLen;}}
Dado que size_typepara una cadena es unsigned, su >=verificación en la condición de bucle siempre será true. Tienes que usarlo std::string::nposallí.
Pavel Minaev
size_type no está sin firmar. No está firmado en muchas plataformas, pero no en todas.
Alan
12
¿Por qué en el mundo esto no es parte de std :: string? ¿Existe alguna otra clase String seria en el mundo de la programación que no ofrezca una operación de 'buscar y reemplazar'? Seguramente es más común que tener dos iteradores y querer reemplazar el texto entre ellos. A veces, std :: string se siente como un automóvil con un parabrisas de espectro sintonizable pero sin forma de bajar la ventanilla del conductor.
Spike0xff
@ Spike0xff boost tieneroll_down_window
ta.speot.es el
1
@gustafr: Mi error. He trabajado en sistemas donde los compiladores más antiguos definieron size_t incorrectamente.
Alan
1
// Replace all occurrences of searchStr in str with replacer// Each match is replaced only once to prevent an infinite loop// The algorithm iterates once over the input and only concatenates // to the output, so it should be reasonably efficient
std::string replace(const std::string& str,const std::string& searchStr,const std::string& replacer){// Prevent an infinite loop if the input is emptyif(searchStr ==""){return str;}
std::string result ="";size_t pos =0;size_t pos2 = str.find(searchStr, pos);while(pos2 != std::string::npos){
result += str.substr(pos, pos2-pos)+ replacer;
pos = pos2 + searchStr.length();
pos2 = str.find(searchStr, pos);}
result += str.substr(pos, str.length()-pos);return result;}
Solo necesitamos buscar nuevas coincidencias desde la última coincidencia, por eso el algoritmo rastrea cuidadosamente la última coincidencia en pos. pos2 siempre almacena la siguiente coincidencia, por lo que concatenamos la cadena entre pos y pos2 al resultado, luego avanzamos pos y pos2. Si no se puede encontrar otra coincidencia, concatenamos el resto de la cadena al resultado.
Respuestas:
¿Por qué no implementar su propio reemplazo?
fuente
Aquí está la documentación oficial sobre replace_all.
fuente
replace_all
se producirá un error de segmentación para las versiones de boost> 1.43 en Sun Studio para cualquier versión <12.3boost
aumenta considerablemente el tiempo de compilación en dispositivos integrados. Incluso ARMv7 de cuatro núcleos. Se compilan 100 líneas de código en 2 minutos, sin impulso, 2 segundos.En C ++ 11, puede hacer esto como una línea con una llamada a
regex_replace
:salida:
fuente
from
puede ser una expresión regular, por lo que puede utilizar criterios de coincidencia más sofisticados si es necesario. Lo que no veo es cómo hacer esto sin aplicar alguna forma de análisis de expresiones regulares, en lugar de usar solo una interpretación directa de losfrom
caracteres.¿Por qué no devolver una cadena modificada?
Si necesita rendimiento, aquí hay una función optimizada que modifica la cadena de entrada, no crea una copia de la cadena:
Pruebas:
Salida:
fuente
Mi búsqueda y reemplazo en línea en el lugar con plantilla:
Devuelve un recuento del número de elementos sustituidos (para usar si desea ejecutar esto sucesivamente, etc.). Para usarlo:
fuente
La forma más fácil (ofreciendo algo parecido a lo que escribió) es usar Boost.Regex , específicamente regex_replace .
std :: string tiene incorporados los métodos find () y replace (), pero es más complicado trabajar con ellos ya que requieren lidiar con índices y longitudes de cadenas.
fuente
Creo que esto funcionaría. Toma const char * como parámetro.
fuente
size_type
para una cadena esunsigned
, su>=
verificación en la condición de bucle siempre serátrue
. Tienes que usarlostd::string::npos
allí.roll_down_window
fuente
La comprobación de que oldStr esté vacía es importante. Si por alguna razón ese parámetro está vacío, se quedará atascado en un bucle infinito.
Pero sí, use la solución probada C ++ 11 o Boost si puede.
fuente