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 j'aimerais utiliser les bibliothèques Standard C ++.
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 j'aimerais utiliser les bibliothèques Standard C ++.
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'
}
}
from
et sont -ils to
passés par const
référence? Quelle est votre fonction si ce from
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 valides
const
revient à ne pas tenir compte de l'un des meilleurs outils de C ++. Le passage par const
ré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- 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.
std::regex_replace
n'accepte pas la chaîne de Qt.
string
par string.toStdString()
.
String
en std::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 une replace
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()
et replace()
.
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
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.
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
)
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'à 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
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
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;
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:
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";
}
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;
}
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(), "\\", "/"), ":", "");
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);
}
}
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;
}
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;
}