@poly Je pense que cela a dû être demandé pour C ++ aussi, mais je ne le trouve pas
Michael Mrozek
1
Il y a une balise std sur la question, mais peut-être que vous pourriez être intéressé par les algorithmes de chaîne de boost, qui incluent également un large choix d'algorithmes de remplacement (inplace / copy, case sensitive / case insensitive, replace first / last / all / n-th ).
Il existe une fonction pour trouver une sous-chaîne 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 souhaité:
Comment le réparerais-je si la chaîne d'origine avait plus d'une instance de "$ name" et que je voulais toutes les remplacer.
Tom Leese
2
Pourquoi ne le sont pas fromet sont -ils topassés par constréférence? Quelle est votre fonction si ce fromn'est pas là? -1de moi pour ça.
sbi
10
@sbi Fixe, même si vous auriez pu le formuler sous forme de recommandations au lieu d'attaques - cela ne m'est tout simplement pas venu à l'esprit, je pense rarement à l'utiliser constet si j'écrivais une méthode utilitaire comme celle-ci, je ne l'appellerais que si je connaissais le remplacement étaient valides
Michael Mrozek
11
@Michael: Bien, j'ai transformé mon vote défavorable en vote favorable. Le rejet constrevient à ne pas tenir compte de l'un des meilleurs outils de C ++. Le passage par constréférence doit être le mode par défaut pour les paramètres de fonction. (FTR, sans le const, vous ne pourriez même pas passer des chaînes littérales à votre fonction, car vous ne pouvez pas lier des temporaires à des non- constréférences. Ainsi, la fonction ne ferait même pas ce sur quoi elle a été écrite.)
sbi
26
Est-ce toujours la seule solution en 2018? Si tel est le cas et qu'un comité C ++ lit ceci, triez-le. C'est gênant. diviser (chaîne, chaîne) et remplacer (chaîne, chaîne) s'il vous plaît!
user997112
104
Avec C ++ 11, vous pouvez utiliser std::regexcomme ceci:
Je suis presque sûr qu'il std::regex_replacen'accepte pas la chaîne de Qt.
BartoszKP
1
Tu as raison. En l'occurrence, QString fournit une méthode de remplacement qui accepte un QRexExp, permettant d'utiliser les propres trucs de Qt. Mais je pense que la réponse actuelle pourrait être corrigée en remplaçant stringpar string.toStdString().
Tom
1
Ou simplement en changeant Stringen std::string, car la question n'est pas liée à Qt. Veuillez envisager de le faire - je serai ravi de voter par la suite.
BartoszKP
6
La chaîne brute permet d'écrire à la R"(\$name)"place de "\\$name".
Jarod42
5
Dans quelle mesure cela sera-t-il plus lent que find / replace sans tenir compte du temps de construction de std :: regex?
jw_
20
std::stringa une replaceméthode, est-ce ce que vous recherchez?
Votre appel à subject.replace dans ReplaceStringInPlace () modifie-t-il vraiment la chaîne en place?
Damian
J'ai brièvement regardé la source et il semble qu'il utilise la sémantique de déplacement pour déplacer l'avant de l'ancienne chaîne en place, de sorte que ce ne soit pas copié, mais le nouveau morceau inséré est copié dans l'ancienne chaîne et la queue de l'ancienne chaîne est copié dans la mémoire tampon redimensionnée de l'ancienne chaîne. Il est possible que la chaîne se développe tellement que tout le tampon sous-jacent soit réalloué, mais si vous remplacez 1 à 1 comme dans son exemple, je pense que cela se produit "en place", ou sans aucune copie, mais si vous développez la chaîne, seule la première partie de l'ancienne chaîne n'est pas copiée, et peut-être alors seulement.
Motes
6
Oui, vous pouvez le faire, mais vous devez trouver la position de la première chaîne avec le membre find () de la chaîne, puis la remplacer par son membre replace ().
Si vous prévoyez d'utiliser la bibliothèque standard, vous devriez vraiment vous procurer un exemplaire du livre The C ++ Standard Library qui couvre très bien tout cela.
Vous pouvez intégrer cela dans une fonction, mais cette solution en une ligne semble acceptable. Le problème est que cela ne changera que la première occurrence, vous voudrez peut-être faire une boucle dessus, mais cela vous permet également d'insérer plusieurs variables dans cette chaîne avec le même jeton ( %s)
Il appelle std::string::find()à plusieurs reprises pour localiser d'autres occurrences de la chaîne recherchée jusqu'à ce std::string::find()qu'il 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 toutes les chaînes sont std :: string, vous rencontrerez des problèmes étranges avec la coupure des caractères si vous l'utilisez sizeof()car elle est destinée aux chaînes C, pas aux chaînes C ++. Le correctif consiste à utiliser la .size()méthode de classe de std::string.
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 vous voulez le faire rapidement, vous pouvez utiliser une approche à deux analyses. Pseudo code:
première analyse. trouver le nombre de caractères correspondants.
étendre la longueur de la chaîne.
deuxième analyse. Commencez par 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 un algorithme en place.
Et un exemple de code C ++ 11 mais je ne recherche qu'un seul caractère.
J'apprends tout juste le C ++, mais en éditant une partie du code précédemment publié, j'utiliserais probablement quelque chose comme ça. Cela vous donne la possibilité de remplacer une ou plusieurs instances et vous permet également de spécifier le point de départ.
usingnamespacestd;
// returns number of replacements made in stringlongstrReplace(string& str, conststring& from, conststring& to, size_t start = 0, long count = -1){
if (from.empty()) return0;
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;
}
Réponses:
Il existe une fonction pour trouver une sous-chaîne 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 souhaité: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
cela ressemblerait probablement à 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' } }
la source
from
et sont -ilsto
passés parconst
référence? Quelle est votre fonction si cefrom
n'est pas là?-1
de moi pour ça.const
et si j'écrivais une méthode utilitaire comme celle-ci, je ne l'appellerais que si je connaissais le remplacement étaient validesconst
revient à ne pas tenir compte de l'un des meilleurs outils de C ++. Le passage parconst
référence doit être le mode par défaut pour les paramètres de fonction. (FTR, sans leconst
, vous ne pourriez même pas passer des chaînes littérales à votre fonction, car vous ne pouvez pas lier des temporaires à des non-const
références. Ainsi, la fonction ne ferait même pas ce sur quoi elle a été écrite.)Avec C ++ 11, vous pouvez utiliser
std::regex
comme ceci:#include <regex> ... std::string string("hello $name"); string = std::regex_replace(string, std::regex("\\$name"), "Somename");
La double barre oblique inverse est requise pour échapper un caractère d'échappement.
la source
std::regex_replace
n'accepte pas la chaîne de Qt.string
parstring.toStdString()
.String
enstd::string
, car la question n'est pas liée à Qt. Veuillez envisager de le faire - je serai ravi de voter par la suite.R"(\$name)"
place de"\\$name"
.std::string
a unereplace
méthode, est-ce ce que vous recherchez?Tu pourrais essayer:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
Je n'ai pas essayé moi-même, lisez simplement la documentation sur
find()
etreplace()
.la source
Pour que la nouvelle chaîne soit renvoyé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 d'entrée, 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(); } }
Tests:
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;
Production:
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
la source
Oui, vous pouvez le faire, mais vous devez trouver la position de la première chaîne avec le membre find () de la chaîne, puis la 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 vous procurer un exemplaire du livre The C ++ Standard Library qui couvre très bien tout cela.
la source
Cela ressemble à une option
string.replace(string.find("%s"), string("%s").size(), "Something");
Vous pouvez intégrer cela dans une fonction, mais cette solution en une ligne semble acceptable. Le problème est que cela ne changera que la première occurrence, vous voudrez peut-être faire une boucle dessus, mais cela vous permet également d'insérer plusieurs variables dans cette chaîne avec le même jeton (
%s
)la source
str.replace(str.find("%s"), string("%s").size(), "Something");
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
std::string::find()
à plusieurs reprises pour localiser d'autres occurrences de la chaîne recherchée jusqu'à cestd::string::find()
qu'il ne trouve rien. Parce questd::string::find()
renvoie la position de la correspondance, nous n'avons pas le problème d'invalider les itérateurs.la source
Si toutes les chaînes sont std :: string, vous rencontrerez des problèmes étranges avec la coupure des caractères si vous l'utilisez
sizeof()
car elle est destinée aux chaînes C, pas aux chaînes C ++. Le correctif consiste à utiliser la.size()
méthode de classe destd::string
.Cela remplace sHaystack en ligne - pas besoin de faire une affectation = à ce sujet.
Exemple d'utilisation:
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;
la source
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);
la source
Si vous voulez le faire rapidement, vous pouvez utiliser une approche à deux analyses. Pseudo code:
Je ne suis pas sûr que cela puisse être optimisé pour un algorithme en place.
Et un exemple de code C ++ 11 mais je ne recherche qu'un seul caractère.
#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"; }
la source
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; }
la source
Ma propre implémentation, en tenant compte du fait que la chaîne ne doit être redimensionnée qu'une seule fois, puis le remplacement peut se produire.
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; }
L'utilisation pourrait être par exemple comme ceci:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
la source
Cela pourrait être encore mieux à utiliser
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); } }
la source
string s = "ha"; replace(s, "h", "uhoh");
J'apprends tout juste le C ++, mais en éditant une partie du code précédemment publié, j'utiliserais probablement quelque chose comme ça. Cela vous donne la possibilité de remplacer une 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; }
la source
Vous pouvez utiliser ce code pour supprimer la sous-chaîne et également remplacer, et également supprimer les espaces blancs supplémentaires. code:
#include<bits/stdc++.h> using namespace std ; void removeSpaces(string &str) { int n = str.length(); int i = 0, j = -1; bool spaceFound = false; while (++j <= n && str[j] == ' '); while (j <= n) { if (str[j] != ' ') { if ((str[j] == '.' || str[j] == ',' || str[j] == '?') && i - 1 >= 0 && str[i - 1] == ' ') str[i - 1] = str[j++]; else str[i++] = str[j++]; spaceFound = false; } else if (str[j++] == ' ') { if (!spaceFound) { str[i++] = ' '; spaceFound = true; } } } if (i <= 1) str.erase(str.begin() + i, str.end()); else str.erase(str.begin() + i - 1, str.end()); } int main() { string s; cin>>s; for(int i=s.find("WUB");i>=0;i=s.find("WUB")) { s.replace(i,3," "); } removeSpaces(s); cout<<s<<endl; return 0; }
la source