617 votes

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

Quelle est la manière efficace de remplacer toutes les occurrences d'un caractère par un autre caractère dans std::string ?

0 votes

Il semble que la stdlib est nulle quand il s'agit de telles fonctionnalités "avancées". Il vaut mieux utiliser QString ou une bibliothèque générale lorsque vous commencez à trouver des éléments manquants.

941voto

Kirill V. Lyadvinsky Points 47627

std::string ne contient pas une telle fonction mais vous pourriez utiliser la fonction autonome replace de l'en-tête algorithm.

#include 
#include 

void some_func() {
  std::string s = "exemple de chaîne";
  std::replace( s.begin(), s.end(), 'x', 'y'); // remplace tous les 'x' par des 'y'
}

10 votes

std::string est un conteneur spécifiquement conçu pour fonctionner avec des séquences de caractères. lien

230 votes

Malheureusement, cela permet de remplacer seulement un caractère par un autre caractère. Il ne peut pas remplacer un caractère par plusieurs caractères (c'est-à-dire par une chaîne). Existe-t-il un moyen de faire une recherche-remplacement avec plusieurs caractères?

7 votes

@Kirill V. Lyadvinsky Que se passe-t-il si je veux simplement supprimer une occurrence.

165voto

Gauthier Boaglio Points 3568

La question est centrée sur le remplacement de character, mais, comme j'ai trouvé cette page très utile (surtout le commentaire de Konrad), je voudrais partager cette implémentation plus généralisée, qui permet de traiter aussi des 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(); // Gère le cas où 'to' est une sous-chaîne de 'from'
    }
    return str;
}

Utilisation:

std::cout << ReplaceAll(string("Nombre De Haricots"), 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;

Résultats:

Nombre_De_Haricots

XXjXugtXty

hhjhugthty


ÉDITER:

L'approche ci-dessus peut être implémentée de manière plus adaptée, au cas où la performance est une préoccupation, en ne renvoyant rien (void) et en effectuant les modifications "en place"; c'est-à-dire, en modifiant directement l'argument de chaîne str, passé par référence au lieu de par valeur. Cela éviterait une copie coûteuse supplémentaire de la chaîne d'origine en l'écrasant.

Code:

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Même code interne...
    // Pas de déclaration de retour
}

En espérant que cela sera utile pour d'autres...

6 votes

Cette fonction présente un problème de performance dans les cas où la chaîne source est grande et où il y a de nombreuses occurrences de la chaîne à remplacer. string::replace() serait appelé de nombreuses fois, ce qui entraîne de nombreuses copies de chaîne. Consultez ma solution qui résout ce problème.

1 votes

Chipotage à venir : par adresse => par référence. Que ce soit une adresse ou non est un détail d'implémentation.

1 votes

Vous devriez en fait vérifier si la chaîne from est vide, sinon une boucle infinie se produira.

150voto

UncleZeiv Points 9033

Je pensais ajouter également la solution boost :

#include 

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

// copie
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");

0 votes

Ensuite, il vous manque quelques drapeaux -I pour votre compilateur afin qu'il puisse trouver les bibliothèques Boost sur votre système. Peut-être devez-vous même l'installer d'abord.

0 votes

Le code ci-dessus est plus efficace car il utilise la bibliothèque standard. Pas besoin d'utiliser la bibliothèque Boost ;-)

25voto

T.E.D. Points 26829

Une simple recherche et remplacement pour un seul caractère se ferait quelque chose comme suit :

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

Pour le faire pour toute la chaîne de caractères, la chose facile à faire serait de boucler jusqu'à ce que votre s.find commence à renvoyer npos. Je suppose que vous pourriez également attraper range_error pour sortir de la boucle, mais c'est plutôt moche.

8 votes

Tandis que c'est probablement une solution adaptée lorsque le nombre de caractères à remplacer est faible par rapport à la longueur de la chaîne, cela ne s'adapte pas bien. À mesure que la proportion de caractères dans la chaîne d'origine qui doivent être remplacés augmente, cette méthode approchera O(N^2) en temps.

7 votes

Vrai. Ma philosophie générale est de faire la chose facile (à écrire et à lire) jusqu'à ce que les inefficacités causent de réels problèmes. Il y a des circonstances où vous pourriez avoir des chaînes énormes où O(N**2) compte, mais 99% du temps mes chaînes sont de 1K ou moins.

4 votes

...Cela étant dit, je préfère la méthode de Kirill (et l'avais déjà votée).

4voto

Konrad Points 8333

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

Alternativement, vous pouvez utiliser la méthode find ou find_first_of en fonction de vos besoins. Aucune de ces solutions ne fera le travail en une seule fois, mais avec quelques lignes de code supplémentaires, vous devriez les rendre fonctionnels. :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X