Remplacer une partie d'une chaîne par une autre chaîne
est-il possible en C++ de remplacer une partie d'une chaîne par une autre chaîne?
en gros, je voudrais faire ceci:
QString string("hello $name");
string.replace("$name", "Somename");
mais je voudrais utiliser les bibliothèques C++ Standard.
12 réponses
il y a une fonction pour trouver un substrat dans une chaîne ( find
), et une fonction pour remplacer une plage particulière dans une chaîne par une autre chaîne ( replace
), vous pouvez donc les combiner pour obtenir l'effet que vous voulez:
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 réponse à un commentaire, je pense que replaceAll
ressemblerait probablement à quelque chose comme ceci:
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'
}
}
avec C++11 Vous pouvez utiliser std::regex
comme suit:
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\$name"), "Somename");
le double backslash est nécessaire pour échapper à un caractère de fuite.
std::string
a une méthode replace
, est-ce que c'est ce que vous cherchez?
Vous pouvez essayer:
s.replace(s.find("$name"), sizeof("Somename")-1, "Somename");
Je n'ai pas essayé moi-même, il suffit de lire la documentation sur find()
et replace()
.
pour que la nouvelle chaîne soit retournée utilisez ceci:
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 vous avez besoin de performances, voici une fonction optimisée qui modifie la chaîne de saisie, elle ne crée pas de copie de la chaîne:
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();
}
}
Essais:
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;
sortie:
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
Oui, vous pouvez le faire, mais vous devez trouver la position de la première chaîne avec le membre find() De string, et ensuite remplacer par son membre replace ().
string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
s.replace( pos, 5, "somename" ); // 5 = length( $name )
}
si vous prévoyez d'utiliser la bibliothèque Standard, vous devriez vraiment obtenir une copie du livre la bibliothèque standard C++ qui couvre tous ces trucs très bien.
cela ressemble à une option
string.replace(string.find("%s"), string("%s").size(), "Something");
vous pouvez envelopper cela dans une fonction mais cette solution d'une ligne semble acceptable.
Le problème est que cela va changer la première occurence, vous pouvez faire une boucle sur elle, mais il vous permet également d'insérer plusieurs variables dans cette chaîne avec le même jeton ( %s
)
si toutes les chaînes sont std::string, vous trouverez des problèmes étranges avec la coupure des caractères si vous utilisez sizeof()
parce que c'est destiné aux chaînes C, pas aux chaînes C++. Le correctif est d'utiliser la méthode de classe .size()
de std::string
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Qui remplace sHaystack en ligne, pas besoin de faire une affectation = sur ce retour.
exemple d'usage:
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;
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;
}
j'utilise généralement ceci:
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;
}
il appelle à plusieurs reprises std::string::find()
pour localiser d'autres occurrences de la chaîne recherchée jusqu'à ce que std::string::find()
ne trouve rien. Parce que std::string::find()
renvoie la position de la correspondance nous n'avons pas le problème d'invalider les itérateurs.
Si vous voulez le faire rapidement, vous pouvez utiliser une des deux scan approche. Pseudo code:
- première analyse. trouvez le nombre de caractères correspondant.
- étendre la longueur de la chaîne.
- deuxième analyse. Commencez à partir de la fin de la chaîne lorsque nous obtenons une correspondance que nous remplaçons, sinon nous copions simplement les caractères de la première chaîne.
Je ne suis pas sûr que cela puisse être optimisé pour une algo en place.
et un exemple de code C++11 mais je ne cherche qu'un seul 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, '"151900920"');
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";
}
je viens juste d'apprendre le C++, mais en éditant une partie du code précédemment posté, j'utiliserais probablement quelque chose comme ça. Cela vous donne la possibilité de remplacer 1 ou plusieurs instances, et vous permet également de spécifier le point de départ.
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;
}
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);