¿Cómo podría reemplazar una subcadena en una cadena con otra subcadena en C ++, qué funciones podría usar?
eg: string test = "abc def abc def";
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring
Respuestas:
No hay una función incorporada en C ++ para hacer esto. Si desea reemplazar todas las instancias de una subcadena con otra, puede hacerlo mezclando llamadas a
string::find
ystring::replace
. Por ejemplo:size_t index = 0; while (true) { /* Locate the substring to replace. */ index = str.find("abc", index); if (index == std::string::npos) break; /* Make the replacement. */ str.replace(index, 3, "def"); /* Advance index forward so the next iteration doesn't pick it up as well. */ index += 3; }
En la última línea de este código, he incrementado
index
la longitud de la cadena que se ha insertado en la cadena. En este ejemplo particular, reemplazar"abc"
con"def"
, esto no es realmente necesario. Sin embargo, en una configuración más general, es importante omitir la cadena que se acaba de reemplazar. Por ejemplo, si desea reemplazar"abc"
con"abcabc"
, sin omitir el segmento de cadena recién reemplazado, este código reemplazaría continuamente partes de las cadenas recién reemplazadas hasta que se agote la memoria. Independientemente, podría ser un poco más rápido omitir esos nuevos personajes de todos modos, ya que hacerlo ahorra algo de tiempo y esfuerzo en lastring::find
función.¡Espero que esto ayude!
fuente
index
) más allá de la parte de la cadena que fue reemplazada.Aumento de la biblioteca de algoritmos de cadena de forma:
#include <boost/algorithm/string/replace.hpp> { // 1. string test = "abc def abc def"; boost::replace_all(test, "abc", "hij"); boost::replace_all(test, "def", "klm"); } { // 2. string test = boost::replace_all_copy ( boost::replace_all_copy<string>("abc def abc def", "abc", "hij") , "def" , "klm" ); }
fuente
En c ++ 11, puedes usar
std::regex_replace
:#include <string> #include <regex> std::string test = "abc def abc def"; test = std::regex_replace(test, std::regex("def"), "klm");
fuente
Creo que todas las soluciones fallarán si la longitud de la cadena de reemplazo es diferente de la longitud de la cadena a reemplazar. (busque "abc" y reemplácelo por "xxxxxx") Un enfoque general podría ser:
void replaceAll( string &s, const string &search, const string &replace ) { for( size_t pos = 0; ; pos += replace.length() ) { // Locate the substring to replace pos = s.find( search, pos ); if( pos == string::npos ) break; // Replace by erasing and inserting s.erase( pos, search.length() ); s.insert( pos, replace ); } }
fuente
Dónde
str
es la cadena basestr2
es la subcadena para encontrarstr3
es la subcadena de reemplazofuente
Reemplazar subcadenas no debería ser tan difícil.
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 rendimiento, aquí hay una función optimizada que modifica la cadena de entrada, no crea 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 changed: " << 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
fuente
if (search.empty()) { return; }
para evitar un bucle infinito cuando se pasa una 'búsqueda' vacía.using std::string; string string_replace( string src, string const& target, string const& repl) { // handle error situations/trivial cases if (target.length() == 0) { // searching for a match to the empty string will result in // an infinite loop // it might make sense to throw an exception for this case return src; } if (src.length() == 0) { return src; // nothing to match against } size_t idx = 0; for (;;) { idx = src.find( target, idx); if (idx == string::npos) break; src.replace( idx, target.length(), repl); idx += repl.length(); } return src; }
Como no es miembro de la
string
clase, no permite una sintaxis tan agradable como en su ejemplo, pero lo siguiente hará el equivalente:test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")
fuente
Generalizando la respuesta de rotmax, aquí hay una solución completa para buscar y reemplazar todas las instancias en una cadena. Si ambas subcadenas son de diferente tamaño, la subcadena se reemplaza usando string :: erase y string :: insert., De lo contrario, se usa la string :: replace más rápida.
void FindReplace(string& line, string& oldString, string& newString) { const size_t oldSize = oldString.length(); // do nothing if line is shorter than the string to find if( oldSize > line.length() ) return; const size_t newSize = newString.length(); for( size_t pos = 0; ; pos += newSize ) { // Locate the substring to replace pos = line.find( oldString, pos ); if( pos == string::npos ) return; if( oldSize == newSize ) { // if they're same size, use std::string::replace line.replace( pos, oldSize, newString ); } else { // if not same size, replace by erasing and inserting line.erase( pos, oldSize ); line.insert( pos, newString ); } } }
fuente
Si está seguro de que la subcadena requerida está presente en la cadena, esto reemplazará la primera aparición de
"abc"
to"hij"
test.replace( test.find("abc"), 3, "hij");
Se bloqueará si no tiene "abc" en la prueba, así que úselo con cuidado.
fuente
Aquí hay una solución que escribí usando la táctica del constructor:
#include <string> #include <sstream> using std::string; using std::stringstream; string stringReplace (const string& source, const string& toReplace, const string& replaceWith) { size_t pos = 0; size_t cursor = 0; int repLen = toReplace.length(); stringstream builder; do { pos = source.find(toReplace, cursor); if (string::npos != pos) { //copy up to the match, then append the replacement builder << source.substr(cursor, pos - cursor); builder << replaceWith; // skip past the match cursor = pos + repLen; } } while (string::npos != pos); //copy the remainder builder << source.substr(cursor); return (builder.str()); }
Pruebas:
void addTestResult (const string&& testId, bool pass) { ... } void testStringReplace() { string source = "123456789012345678901234567890"; string toReplace = "567"; string replaceWith = "abcd"; string result = stringReplace (source, toReplace, replaceWith); string expected = "1234abcd8901234abcd8901234abcd890"; bool pass = (0 == result.compare(expected)); addTestResult("567", pass); source = "123456789012345678901234567890"; toReplace = "123"; replaceWith = "-"; result = stringReplace(source, toReplace, replaceWith); expected = "-4567890-4567890-4567890"; pass = (0 == result.compare(expected)); addTestResult("start", pass); source = "123456789012345678901234567890"; toReplace = "0"; replaceWith = ""; result = stringReplace(source, toReplace, replaceWith); expected = "123456789123456789123456789"; pass = (0 == result.compare(expected)); addTestResult("end", pass); source = "123123456789012345678901234567890"; toReplace = "123"; replaceWith = "-"; result = stringReplace(source, toReplace, replaceWith); expected = "--4567890-4567890-4567890"; pass = (0 == result.compare(expected)); addTestResult("concat", pass); source = "1232323323123456789012345678901234567890"; toReplace = "323"; replaceWith = "-"; result = stringReplace(source, toReplace, replaceWith); expected = "12-23-123456789012345678901234567890"; pass = (0 == result.compare(expected)); addTestResult("interleaved", pass); source = "1232323323123456789012345678901234567890"; toReplace = "==="; replaceWith = "-"; result = utils_stringReplace(source, toReplace, replaceWith); expected = source; pass = (0 == result.compare(expected)); addTestResult("no match", pass); }
fuente
string & replace(string & subj, string old, string neu) { size_t uiui = subj.find(old); if (uiui != string::npos) { subj.erase(uiui, old.size()); subj.insert(uiui, neu); } return subj; }
¡Creo que esto se ajusta a sus requisitos con pocos códigos!
fuente
la versión mejorada de @Czarek Tomczak.
permitir ambos
std::string
ystd::wstring
.template <typename charType> void ReplaceSubstring(std::basic_string<charType>& subject, const std::basic_string<charType>& search, const std::basic_string<charType>& replace) { if (search.empty()) { return; } typename std::basic_string<charType>::size_type pos = 0; while((pos = subject.find(search, pos)) != std::basic_string<charType>::npos) { subject.replace(pos, search.length(), replace); pos += replace.length(); } }
fuente
std::string replace(const std::string & in , const std::string & from , const std::string & to){ if(from.size() == 0 ) return in; std::string out = ""; std::string tmp = ""; for(int i = 0, ii = -1; i < in.size(); ++i) { // change ii if ( ii < 0 && from[0] == in[i] ) { ii = 0; tmp = from[0]; } else if( ii >= 0 && ii < from.size()-1 ) { ii ++ ; tmp = tmp + in[i]; if(from[ii] == in[i]) { } else { out = out + tmp; tmp = ""; ii = -1; } } else { out = out + in[i]; } if( tmp == from ) { out = out + to; tmp = ""; ii = -1; } } return out; };
fuente
Aquí hay una solución que usa la recursividad que reemplaza todas las apariciones de una subcadena con otra subcadena. Esto funciona sin importar el tamaño de las cuerdas.
std::string ReplaceString(const std::string source_string, const std::string old_substring, const std::string new_substring) { // Can't replace nothing. if (old_substring.empty()) return source_string; // Find the first occurrence of the substring we want to replace. size_t substring_position = source_string.find(old_substring); // If not found, there is nothing to replace. if (substring_position == std::string::npos) return source_string; // Return the part of the source string until the first occurance of the old substring + the new replacement substring + the result of the same function on the remainder. return source_string.substr(0,substring_position) + new_substring + ReplaceString(source_string.substr(substring_position + old_substring.length(),source_string.length() - (substring_position + old_substring.length())), old_substring, new_substring); }
Ejemplo de uso:
std::string my_cpp_string = "This string is unmodified. You heard me right, it's unmodified."; std::cout << "The original C++ string is:\n" << my_cpp_string << std::endl; my_cpp_string = ReplaceString(my_cpp_string, "unmodified", "modified"); std::cout << "The final C++ string is:\n" << my_cpp_string << std::endl;
fuente
std::string replace(std::string str, std::string substr1, std::string substr2) { for (size_t index = str.find(substr1, 0); index != std::string::npos && substr1.length(); index = str.find(substr1, index + substr2.length() ) ) str.replace(index, substr1.length(), substr2); return str; }
Solución corta donde no necesita bibliotecas adicionales.
fuente
std::string replace(std::string str, const std::string& sub1, const std::string& sub2) { if (sub1.empty()) return str; std::size_t pos; while ((pos = str.find(sub1)) != std::string::npos) str.replace(pos, sub1.size(), sub2); return str; }
fuente