2010-08-05 17 views
141

¿Es posible en C++ reemplazar parte de una cadena por otra cuerda?Reemplazar parte de una cadena con otra cadena

Básicamente, me gustaría hacer esto:

QString string("hello $name"); 
string.replace("$name", "Somename"); 

Pero me gustaría usar las bibliotecas estándar de C++.

+0

posible duplicado de [¿Cuál es la función de reemplazar cadena en C?] (Http://stackoverflow.com/questions/779875/what-is-the-function-to-replace-string-in- c) - ¡Vaya, lo siento, es C, no C++; Desearía poder dejar de votar. – polygenelubricants

+2

¿Por qué esto tiene una etiqueta 'C'? – sbi

+1

@poly Creo que esto también debe haber sido preguntado por C++, pero no puedo encontrarlo –

Respuesta

219

Hay una función para encontrar una subcadena dentro de una cadena (find), y una función para reemplazar un rango particular en una cadena con otra cadena (replace), por lo que se pueden combinar los para obtener el efecto deseado:

bool replace(std::string& str, const std::string& from, const std::string& to) { 
    size_t start_pos = str.find(from); 
    if(start_pos == std::string::npos) 
     return false; 
    str.replace(start_pos, from.length(), to); 
    return true; 
} 

std::string string("hello $name"); 
replace(string, "$name", "Somename"); 

En respuesta a un comentario, creo replaceAll probablemente algo parecido a esto:

void replaceAll(std::string& str, const std::string& from, const std::string& to) { 
    if(from.empty()) 
     return; 
    size_t start_pos = 0; 
    while((start_pos = str.find(from, start_pos)) != std::string::npos) { 
     str.replace(start_pos, from.length(), to); 
     start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' 
    } 
} 
+2

¿Cómo lo arreglaría si la secuencia original tuviera más de una instancia de "$ name" y quisiera reemplazarlos todos? –

+1

¿Por qué no se pasa 'from' y' to' por 'const' reference? ¿Qué función tiene si 'from' no está allí? '-1' de mí por eso. – sbi

+0

Agregue un bucle y use el argumento "pos" del método find() –

14

std::string tiene un método replace, ¿eso es lo que está buscando?

Usted podría intentar:

s.replace(s.find("$name"), sizeof("Somename")-1, "Somename"); 

No he probado a mí mismo, acabo de leer la documentación sobre find() y replace().

+0

De lo que puedo ver el método std :: string replace no toma dos cadenas como me gustaría. –

+0

Creo que Michael Mrozek tiene una solución más elegante –

+1

Esto no funciona para mí. sizeof debe ser reemplazado por string ("Somename"). size() - 1 – TimZaman

6

Sí, puede hacerlo, pero tiene que encontrar la posición de la primera cadena con el miembro find() de string, y luego reemplazar con su miembro replace().

string s("hello $name"); 
size_type pos = s.find("$name"); 
if (pos != string::npos) { 
    s.replace(pos, 5, "somename"); // 5 = length($name) 
} 

Si usted está planeando sobre el uso de la biblioteca estándar, que realmente debe hacerse con una copia del libro The C++ Standard Library que cubre todo esto muy bien.

+0

Ok, intentaré y escribiré mi propia función para hacer eso. –

+1

es size_t y no size_type – revo

+0

Es std :: string :: size_type, no size_t o sin adornos size_type. – jmucchiello

7

Para que la nueva cadena devuelta uso esto:

std::string ReplaceString(std::string subject, const std::string& search, 
          const std::string& replace) { 
    size_t pos = 0; 
    while ((pos = subject.find(search, pos)) != std::string::npos) { 
     subject.replace(pos, search.length(), replace); 
     pos += replace.length(); 
    } 
    return subject; 
} 

Si necesita el rendimiento, aquí es una función optimizada que modifica la cadena de entrada, no crear una copia de la cadena:

void ReplaceStringInPlace(std::string& subject, const std::string& search, 
          const std::string& replace) { 
    size_t pos = 0; 
    while ((pos = subject.find(search, pos)) != std::string::npos) { 
     subject.replace(pos, search.length(), replace); 
     pos += replace.length(); 
    } 
} 

pruebas :

std::string input = "abc abc def"; 
std::cout << "Input string: " << input << std::endl; 

std::cout << "ReplaceString() return value: " 
      << ReplaceString(input, "bc", "!!") << std::endl; 
std::cout << "ReplaceString() input string not modified: " 
      << input << std::endl; 

ReplaceStringInPlace(input, "bc", "??"); 
std::cout << "ReplaceStringInPlace() input string modified: " 
      << input << std::endl; 

salida:

Input string: abc abc def 
ReplaceString() return value: a!! a!! def 
ReplaceString() input string not modified: abc abc def 
ReplaceStringInPlace() input string modified: a?? a?? def 
+0

Su llamada a subject.replace en ReplaceStringInPlace() ¿realmente está modificando la cadena en el lugar? – Damian

+0

Miré brevemente la fuente y parece que usa la semántica de movimiento para mover la parte delantera de la secuencia anterior a su lugar, para que no se copie, pero la nueva pieza insertada se copia en la cadena anterior y en la cola de la antigua. cadena se copia en el tamaño modificado de la vieja cadena. Es posible que la cadena se expanda tanto que se reasigna todo el buffer subyacente, pero si reemplaza 1 a 1 como en su ejemplo, creo que ocurre "in situ", o sin ninguna copia, pero si expande la cadena, solo la primera parte de la cadena anterior no se copia, y solo tal vez entonces. – Motes

2
std::string replace(std::string base, const std::string from, const std::string to) { 
    std::string SecureCopy = base; 

    for (size_t start_pos = SecureCopy.find(from); start_pos != std::string::npos; start_pos = SecureCopy.find(from,start_pos)) 
    { 
     SecureCopy.replace(start_pos, from.length(), to); 
    } 

    return SecureCopy; 
} 
+2

¿Puede explicar este código (en su respuesta)? ¡Podrías obtener más votos favorables de esa manera! –

1

yo uso generalmente esto:

std::string& replace(std::string& s, const std::string& from, const std::string& to) 
{ 
    if(!from.empty()) 
     for(size_t pos = 0; (pos = s.find(from, pos)) != std::string::npos; pos += to.size()) 
      s.replace(pos, from.size(), to); 
    return s; 
} 

Se llama repetidamente std::string::find() para localizar otras ocurrencias del buscado cuerda hasta std::string::find() no encuentra nada. Como std::string::find() devuelve la posición de la coincidencia, no tenemos el problema de invalidar los iteradores.

+0

Su función de reemplazo() funciona perfectamente. Pero en caso de que la variable ** de ** esté vacía, ingresa en un bucle infinito. std :: string a ("Hola"); reemplazar (a, "", "mundo"); – Hill

+0

@Hill ¡Gracias por descubrir eso! Pensé que 'std :: string :: find' devolvería' npos' si no le daba nada para encontrar, ¡pero aparentemente no! Fijo. – Galik

51

con C++ 11 puede utilizar std::regex este modo: se requiere

std::string string("hello $name"); 
    string = std::regex_replace(string, std::regex("\\$name"), "Somename"); 

La doble barra invertida para escapar de un carácter de escape.

+0

Estoy bastante seguro de que 'std :: regex_replace' no acepta la cadena de Qt. – BartoszKP

+1

Tienes razón. Da la casualidad que QString proporciona un método de reemplazo que acepta un QRexExp, lo que permite usar el propio material de Qt. Pero creo que la respuesta actual podría corregirse reemplazando 'string' con' string.toStdString() '. – Tom

+1

O simplemente cambiando 'String' por' std :: string', porque la pregunta no está relacionada con Qt. Por favor, considere hacer eso; con mucho gusto le devolveré su respuesta. – BartoszKP

4

Esto suena como una opción

string.replace(string.find("%s"), string("%s").size(), "Something");

Usted podría terminar con esto de una función, pero esta solución de una línea suena aceptable. El problema es que esto solo cambiará la primera ocurrencia, es posible que desee recorrerlo, pero también le permite insertar varias variables en esta cadena con el mismo token (%s)

+0

Al igual que el estilo, pero encontró que las diferentes cadenas confundían ^^ 'str.replace (str.find ("% s "), string ("% s "). Size()," Something ");' –

0

Estoy recién aprendiendo C++, pero editando parte del código publicado anteriormente, probablemente usaría algo como esto. Esto le da la flexibilidad de reemplazar 1 o varias instancias, y también le permite especificar el punto de inicio.

using namespace std; 

// returns number of replacements made in string 
long strReplace(string& str, const string& from, const string& to, size_t start = 0, long count = -1) { 
    if (from.empty()) return 0; 

    size_t startpos = str.find(from, start); 
    long replaceCount = 0; 

    while (startpos != string::npos){ 
     str.replace(startpos, from.length(), to); 
     startpos += to.length(); 
     replaceCount++; 

     if (count > 0 && replaceCount >= count) break; 
     startpos = str.find(from, startpos); 
    } 

    return replaceCount; 
} 
0
wstring myString = L"Hello $$ this is an example. By $$."; 
wstring search = L"$$"; 
wstring replace = L"Tom"; 
for (int i = myString.find(search); i >= 0; i = myString.find(search)) 
    myString.replace(i, search.size(), replace); 
3

Si todas las cadenas son std :: string, encontrará problemas extraños con el punto de corte de caracteres si se utiliza sizeof() porque está destinado a cadenas de C, no C++ cadenas. La solución es utilizar el método de clase .size() de std::string.

sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace); 

Eso reemplaza sHaystack en línea - no hay necesidad de hacer una = asignación en eso.

Ejemplo de uso:

std::string sHaystack = "This is %XXX% test."; 
std::string sNeedle = "%XXX%"; 
std::string sReplace = "my special"; 
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace); 
std::cout << sHaystack << std::endl; 
1

Si desea hacerlo de manera rápida se puede utilizar un enfoque de dos escaneo. Pseudocódigo:

  1. primer parse. encuentre cuántos caracteres coincidentes.
  2. expanda la longitud de la cadena.
  3. segundo análisis. Comienza desde el final de la cadena cuando obtenemos una coincidencia que reemplazamos, de lo contrario solo copiamos los caracteres de la primera cadena.

No estoy seguro de si esto se puede optimizar a un lugar en el lugar.

Y un ejemplo de código C++ 11 pero solo busco un char.

#include <string> 
#include <iostream> 
#include <algorithm> 
using namespace std; 

void ReplaceString(string& subject, char search, const string& replace) 
{ 
    size_t initSize = subject.size(); 
    int count = 0; 
    for (auto c : subject) { 
     if (c == search) ++count; 
    } 

    size_t idx = subject.size()-1 + count * replace.size()-1; 
    subject.resize(idx + 1, '\0'); 

    string reverseReplace{ replace }; 
    reverse(reverseReplace.begin(), reverseReplace.end()); 

    char *end_ptr = &subject[initSize - 1]; 
    while (end_ptr >= &subject[0]) 
    { 
     if (*end_ptr == search) { 
      for (auto c : reverseReplace) { 
       subject[idx - 1] = c; 
       --idx;    
      }   
     } 
     else { 
      subject[idx - 1] = *end_ptr; 
      --idx; 
     } 
     --end_ptr; 
    } 
} 

int main() 
{ 
    string s{ "Mr John Smith" }; 
    ReplaceString(s, ' ', "%20"); 
    cout << s << "\n"; 

} 
Cuestiones relacionadas