Comment remplacer toutes les occurrences d'un caractère dans la chaîne?

Quel est le moyen efficace de remplacer toutes les occurrences d'un caractère par un autre caractère dans std::string?

400
demandé sur chema989 2010-05-24 15:30:25

12 réponses

std::string ne contient pas une telle fonction mais vous pouvez utiliser la fonction autonome {[2] } de l'en-tête algorithm.

#include <algorithm>
#include <string>

void some_func() {
  std::string s = "example string";
  std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}
612
répondu Kirill V. Lyadvinsky 2014-02-28 20:12:02

Je pensais aussi lancer la solution boost :

#include <boost/algorithm/string/replace.hpp>

// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");

// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");
111
répondu UncleZeiv 2013-05-16 15:06:42

La question est centrée sur le remplacement de character, mais, comme j'ai trouvé cette page très utile (en particulier la remarque deKonrad ), j'aimerais partager cette implémentation plus généralisée, qui permet de traiter aussi substrings:

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
    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(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

Utilisation:

std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;

Sorties:

Number_Of_Beans

XXjXugtXty

Hhjhugthty


Modifier:

Ce qui précède peut être mis en œuvre d'une manière plus appropriée, dans le cas où les performances sont de votre ressort, en ne renvoyant rien (void) et en effectuant les modifications directement sur la chaîne strdonnée en argument, passée par adresseau lieu de par valeur. Cela éviterait une copie inutile et coûteuse de la chaîne d'origine, tout en renvoyant le résultat. Votre appel, alors...

Code :

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Same inner code...
    // No return statement
}

J'espère que cela sera utile pour d'autres...

97
répondu Gauthier Boaglio 2017-05-23 11:55:07

Imaginez un gros blob binaire où tous les octets 0x00 doivent être remplacés par "\1 \ x30 "et tous les octets 0x01 par" \1 \ x31 " car le protocole de transport n'autorise pas \0-bytes.

Dans les cas où:

  • la chaîne de remplacement et la chaîne à remplacer ont des longueurs différentes,
  • Il existe de nombreuses occurrences de la chaîne à remplacer dans la chaîne source et
  • la chaîne source est grande,

Les solutions fournies ne peuvent pas être appliquées (car elles ne remplacent que les solutions simples caractères) ou ont un problème de performance, car ils appelleraient string::replace plusieurs fois ce qui génère des copies de la taille du blob encore et encore. (Je ne connais pas la solution boost, peut-être que c'est OK de ce point de vue)

Celui-ci parcourt toutes les occurrences de la chaîne source et construit la nouvelle chaîne pièce par pièce Une fois :

void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
    std::string newString;
    newString.reserve(source.length());  // avoids a few memory allocations

    std::string::size_type lastPos = 0;
    std::string::size_type findPos;

    while(std::string::npos != (findPos = source.find(from, lastPos)))
    {
        newString.append(source, lastPos, findPos - lastPos);
        newString += to;
        lastPos = findPos + from.length();
    }

    // Care for the rest after last occurrence
    newString += source.substr(lastPos);

    source.swap(newString);
}
24
répondu minastaros 2017-05-26 18:06:20

Une simple recherche et remplacement pour un seul caractère irait quelque chose comme:

s.replace(s.find("x"), 1, "y")

Pour ce faire pour toute la chaîne, la chose facile à faire serait de boucler jusqu'à ce que votre s.find commence à renvoyer npos. Je suppose que vous pourriez aussi attraper range_error pour quitter la boucle, mais c'est un peu moche.

19
répondu T.E.D. 2010-05-24 11:56:37

Si vous cherchez à remplacer plus d'un seul caractère, et traitez uniquement avec std::string, alors cet extrait fonctionnerait, remplaçant sNeedle dans sHaystack par sReplace, et sNeedle et sReplace n'ont pas besoin d'avoir la même taille. Cette routine utilise la boucle while Pour remplacer toutes les occurrences, plutôt que la première trouvée de gauche à droite.

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
5
répondu Volomike 2016-02-07 00:20:53

Comme Kirill l'a suggéré, utilisez la méthode replace ou itérez le long de la chaîne en remplaçant chaque caractère indépendamment.

Vous pouvez également utiliser la méthode find ou find_first_of en fonction de ce que vous devez faire. Aucune de ces solutions ne fera le travail en une seule fois, mais avec quelques lignes de code supplémentaires, vous devriez les faire fonctionner pour vous. :-)

4
répondu Konrad 2010-05-24 11:36:44
#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
    int len, loop=0;
    string nword="", let;
    len=word.length();
    len--;
    while(loop<=len){
        let=word.substr(loop, 1);
        if(let==target){
            nword=nword+replacement;
        }else{
            nword=nword+let;
        }
        loop++;
    }
    return nword;

}
//Main..
int main() {
  string word;
  cout<<"Enter Word: ";
  cin>>word;
  cout<<replace(word, "x", "y")<<endl;
  return 0;
}
3
répondu Lloydie 2015-02-25 18:58:18

Cela fonctionne! J'ai utilisé quelque chose de similaire à cela pour une application de librairie, où l'inventaire a été stocké dans un CSV (comme un .fichier dat). Mais dans le cas d'un seul caractère, ce qui signifie que le remplaçant n'est qu'un seul caractère, par exemple'|', il doit être entre guillemets doubles "|" afin de ne pas lancer une conversion const char invalide.

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int count = 0;  // for the number of occurences.
    // final hold variable of corrected word up to the npos=j
    string holdWord = "";
    // a temp var in order to replace 0 to new npos
    string holdTemp = "";
    // a csv for a an entry in a book store
    string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";

    // j = npos
    for (int j = 0; j < holdLetter.length(); j++) {

        if (holdLetter[j] == ',') {

            if ( count == 0 ) 
            {           
                holdWord = holdLetter.replace(j, 1, " | ");      
            }
            else {

                string holdTemp1 = holdLetter.replace(j, 1, " | ");

                // since replacement is three positions in length,
                // must replace new replacement's 0 to npos-3, with
                // the 0 to npos - 3 of the old replacement 
                holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3); 

                holdWord = "";

                holdWord = holdTemp;

            }
            holdTemp = "";
            count++;
        }
    } 
    cout << holdWord << endl;
    return 0;
}

// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85

Uncustomarily j'utilise CentOS actuellement, donc ma version du compilateur est ci-dessous . La version C++ (G++), C++98 par défaut:

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0
répondu oOpSgEo 2016-04-30 23:24:10

Si vous êtes prêt à utiliser std::string s, vous pouvez utiliser la fonction strsub de cet exemple d'application telle quelle, ou la mettre à jour si vous voulez qu'elle prenne un type ou un ensemble de paramètres différents pour atteindre à peu près le même objectif. Fondamentalement, il utilise les propriétés et les fonctionnalités de std::string pour effacer rapidement l'ensemble de caractères correspondant, et insérer les caractères souhaités directement dans le std::string. Chaque fois qu'il effectue cette opération de remplacement, le décalage est mis à jour s'il peut toujours trouver des caractères correspondants à remplacer, et s'il impossible en raison de rien de plus à remplacer, il renvoie la chaîne dans son état à partir de la dernière mise à jour.

#include <iostream>
#include <string>

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "yyy", "i");
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "ii", "y");

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, charsToReplace.size());
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
                                           this_occurrence + replacementChars.size());
    }

    return this_string;
}

Si vous ne voulez pas utiliser std::strings comme paramètres pour que vous puissiez passer des chaînes de style C à la place, vous pouvez voir l'exemple mis à jour ci-dessous:

#include <iostream>
#include <string>

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "yyy", "i", 3, 1);
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "ii", "y", 2, 1);

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, sizeOfCharsToReplace);
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
            this_occurrence + sizeOfReplacementChars);
    }

    return this_string;
}
0
répondu kayleeFrye_onDeck 2017-04-15 14:52:53

Pour des situations simples, cela fonctionne assez bien sans utiliser d'autre bibliothèque que std::string (qui est déjà utilisé).

Remplacez toutes les occurences de caractère un, avec caractère b dans chaîne_quelconque:

for (size_t i = 0; i < some_string.size(); ++i) {
    if (some_string[i] == 'a') {
        some_string.replace(i, 1, "b");
    }
}

Si la chaîne est volumineuse ou que plusieurs appels à remplacer posent problème, vous pouvez appliquer la technique mentionnée dans cette réponse: https://stackoverflow.com/a/29752943/3622300

0
répondu Guney Ozsan 2018-01-29 12:46:21

Vieille École : -)

    string pth = "H:/recursos/audio/youtube/libre/falta/";        

    for(int i=0 ;i<=pth.size(); i++)
    if(pth[i]=='/')
    pth[i]='\\';

    cout<<pth;

Résultat: "H:\recursos\audio\youtube\libre\falta\";

0
répondu Iván Rodríguez 2018-05-20 19:55:36