web-dev-qa-db-fra.com

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

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

439
big-z

std::string ne contient pas cette fonction, mais vous pouvez utiliser la fonction autonome replace de algorithm en-tête.

#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'
}
673

Je pensais avoir jeté le solution boost aussi:

#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, "#", "@");
121
UncleZeiv

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

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;
}

Usage:

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;

Les sorties:

Number_Of_Beans

XXjXugtXty

hhjhugthty


EDIT:

Ce qui précède peut être implémenté de manière plus appropriée, au cas où les performances vous intéressent, en ne renvoyant rien (void) et en effectuant les modifications directement sur la chaîne str donnée comme argument, passé par adresse au 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 ...

110
Gauthier Boaglio

Imaginez un blob binaire volumineux dans lequel 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 les\0 octets.

Dans les cas où:

  • les chaînes de remplacement et à 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 des caractères uniques) ou ont un problème de performances, car elles appellent plusieurs fois string :: replace, ce qui génère des copies de la taille de l'objet blob à plusieurs reprises. (Je ne connais pas la solution de boost, peut-être que ça va dans cette perspective)

Celui-ci parcourt toutes les occurrences de la chaîne source et construit la nouvelle chaîne pièce par pièce ne 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);
}
28
minastaros

Une simple recherche et remplacement pour un seul personnage donnerait à peu près la même chose:

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

Pour faire cela 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 sortir de la boucle, mais c'est un peu moche.

20
T.E.D.

Si vous cherchez à remplacer plus d'un caractère et que vous ne vous occupez que de std::string, alors cet extrait fonctionnera, en remplaçant sNeedle dans sHaystack par sReplace, et sNeedle et sReplace n'ont pas besoin d'être de la même taille. Cette routine utilise la boucle while pour remplacer toutes les occurrences, plutôt que la seule qui se trouve de gauche à droite.

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
6
Volomike

Comme Kirill l'a suggéré, utilisez la méthode replace ou effectuez une itération 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 vos tâches. Aucune de ces solutions ne fera le travail en une fois, mais avec quelques lignes de code supplémentaires, vous devriez les faire fonctionner pour vous. :-)

4
Konrad
#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
Lloydie

Pour des situations simples, cela fonctionne plutôt bien sans utiliser aucune autre bibliothèque que std :: string (qui est déjà utilisée).

Remplacez toutes les occurrences de caractère a par un caractère b dans quelque_chaîne :

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 longue ou si plusieurs appels à remplacer constituent un problème, vous pouvez appliquer la technique mentionnée dans cette réponse: https://stackoverflow.com/a/29752943/36223

0
Guney Ozsan

Si vous voulez utiliser std::strings, vous pouvez utiliser la fonction strsub de cet exemple d'application, ou la mettre à jour si vous souhaitez qu'elle prenne un type ou un ensemble de paramètres différent même objectif. Fondamentalement, il utilise les propriétés et les fonctionnalités de std::string pour effacer rapidement le jeu 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, l'offset se met à jour s'il peut toujours trouver des caractères correspondants à remplacer, et s'il ne peut rien remplacer, il renvoie la chaîne dans son état depuis 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 souhaitez pas utiliser les paramètres std::strings pour pouvoir passer des chaînes de style C, 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
kayleeFrye_onDeck

Vieille école :-)

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

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

std::cout << str;

Résultat:

H:\recursos\audio\youtube\libre\falta \

0
Iván Rodríguez

Cela marche! J'ai utilisé quelque chose de similaire à ceci pour une application de librairie, où l'inventaire était stocké dans un fichier CSV (comme un fichier .dat). Mais dans le cas d’un caractère unique, le remplaçant n’est qu’un seul caractère, par exemple, '|', il doit être placé entre guillemets "|" afin de ne pas jeter un caractère de conversion 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

De façon inhabituelle, 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
oOpSgEo