¿Es posible en C ++ 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 ++.
¿Es posible en C ++ 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 ++.
Respuestas:
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
), para que pueda combinarlas para obtener el efecto que desea:
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
que probablemente se vería así:
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'
}
}
from
y se to
pasan por const
referencia? ¿Cuál es su función si from
no está allí? -1
de mi parte por eso.
const
y si escribiera un método de utilidad como este solo lo llamaría si supiera el reemplazo eran válidas
const
es ignorar una de las mejores herramientas de C ++. El paso por const
referencia debe ser el modo predeterminado para los parámetros de función. (FTR, sin el const
, que ni siquiera podía pasar literales de cadena a su función, porque no se pueden temporales se unen a los no const
referencias Así la función ni siquiera hacer lo que fue escrito para..)
Con C ++ 11 puede usar std::regex
así:
#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");
La barra invertida doble es necesaria para escapar de un personaje de escape.
std::regex_replace
que no acepta la cadena de Qt.
string
con string.toStdString()
.
String
a std::string
, porque la pregunta no está relacionada con Qt. Por favor considere hacer eso. Con mucho gusto votaré su respuesta después.
R"(\$name)"
lugar de "\\$name"
.
std::string
tiene un replace
método, ¿es eso lo que estás buscando?
Tu podrías intentar:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
No lo he probado yo mismo, solo leí la documentación en find()
y replace()
.
Para que se devuelva la nueva cadena, use 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 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 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
Sí, puede hacerlo, pero debe encontrar la posición de la primera cadena con el miembro find () de la cadena y luego reemplazarla 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 está planeando usar la Biblioteca estándar, debería obtener una copia del libro La biblioteca estándar de C ++ que cubre todo esto muy bien.
Generalmente uso 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;
}
Llama repetidamente std::string::find()
para localizar otras ocurrencias de la cadena buscada hasta std::string::find()
que no encuentra nada. Porque std::string::find()
devuelve el posición de la coincidencia, no tenemos el problema de invalidar iteradores.
Esto suena como una opción
string.replace(string.find("%s"), string("%s").size(), "Something");
Podría envolver esto en una función, pero esta solución de una línea parece 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
)
str.replace(str.find("%s"), string("%s").size(), "Something");
Si todas las cadenas son std :: string, encontrará problemas extraños con el corte de caracteres si se usa sizeof()
porque está destinado a cadenas C, no a cadenas C ++. La solución es usar el .size()
método de clase de std::string
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Eso reemplaza a sHaystack en línea: no es necesario hacer una asignación = de nuevo 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;
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);
Si desea hacerlo rápidamente, puede usar un enfoque de dos escaneos. Pseudocódigo:
No estoy seguro de si esto puede optimizarse para algo en el lugar.
Y un ejemplo de código C ++ 11 pero solo busco un carácter.
#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";
}
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;
}
Mi propia implementación, teniendo en cuenta que la cadena debe redimensionarse solo una vez, luego puede reemplazarse.
template <typename T>
std::basic_string<T> replaceAll(const std::basic_string<T>& s, const T* from, const T* to)
{
auto length = std::char_traits<T>::length;
size_t toLen = length(to), fromLen = length(from), delta = toLen - fromLen;
bool pass = false;
std::string ns = s;
size_t newLen = ns.length();
for (bool estimate : { true, false })
{
size_t pos = 0;
for (; (pos = ns.find(from, pos)) != std::string::npos; pos++)
{
if (estimate)
{
newLen += delta;
pos += fromLen;
}
else
{
ns.replace(pos, fromLen, to);
pos += delta;
}
}
if (estimate)
ns.resize(newLen);
}
return ns;
}
El uso podría ser, por ejemplo, así:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
Ahora estoy aprendiendo C ++, pero editando parte del código publicado anteriormente, probablemente usaría algo como esto. Esto le brinda 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;
}
Esto podría ser incluso mejor usar
void replace(string& input, const string& from, const string& to)
{
while(true)
{
size_t startPosition = input.find(from);
if(startPosition == string::npos)
break;
input.replace(startPosition, from.length(), to);
}
}