Comment supprimer toutes les occurrences d'un caractère dans une chaîne C ++


98

J'utilise ce qui suit:

replace (str1.begin(), str1.end(), 'a' , '')

Mais cela donne une erreur de compilation.


8
''n'est en effet pas un personnage.
n. «pronoms» m.

4
Eh bien, il serait certainement utile de connaître l'erreur que vous obtenez.
SBI

3
soyez gentil, il y a beaucoup de contextes où remplacer est une pensée appropriée, mais pas celle-ci.
RichardPlunkett

Réponses:


171

Fondamentalement, replaceremplace un caractère par un autre et ''n'est pas un personnage. Ce que vous recherchez, c'est erase.

Voir cette question qui répond au même problème. Dans ton cas:

#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

Ou utilisez boostsi c'est une option pour vous, comme:

#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");

Tout cela est bien documenté sur les sites Web de référence . Mais si vous ne connaissez pas ces fonctions, vous pouvez facilement faire ce genre de choses à la main:

std::string output;
output.reserve(str.size()); // optional, avoids buffer reallocations in the loop
for(size_t i = 0; i < str.size(); ++i)
  if(str[i] != 'a') output += str[i];

2
N'est-ce pas l'algorithme que vous avez fourni O(n^2)?
jww

@jww: Je suppose que vous parlez du dernier exemple de code et qu'il ns'agit de la longueur de chaîne d'origine. Pour chaque caractère d'entrée, je fais 1 test de caractère O(1)et 0 ou 1 caractère ajouté. L'ajout de caractères O(1)est une quantité suffisante de mémoire réservée ou O(current_length)si un nouveau tampon est alloué. Si vous le faites output.reserve(str.size())avant la boucle, cela ne se produit jamais et vous avez un O(n)coût global . Sinon, de manière asymptotique, je suppose que le coût est O(n . log(n) )dû à la stratégie de réallocation des conteneurs STL.
Antoine

5
J'avais besoin de #include <algorithm>
S Meaden

Bonne réponse. C'est toujours bien si la réponse contient de nombreuses solutions. Pour moi, la solution avec le forest la plus adaptée.
Dmitry Nichiporenko

@DmitryNichiporenko la réponse avec le pour ne peut pas être la plus appropriée. Si vous avez un prédicat ou une sortie non vide, je préfère considérer: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (sortie), [] (char c) {return predicate (c);});
jimifiki

10

L'algorithme std::replacefonctionne par élément sur une séquence donnée (il remplace donc les éléments par des éléments différents, et ne peut pas le remplacer par rien ). Mais il n'y a pas de caractère vide . Si vous souhaitez supprimer des éléments d'une séquence, les éléments suivants doivent être déplacés et std::replacene fonctionnent pas comme ceci.

Vous pouvez essayer d'utiliser std::remove( avecstd::erase ) pour y parvenir.

str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

8

Utilisation copy_if:

#include <string>
#include <iostream>
#include <algorithm>
int main() {
    std::string s1 = "a1a2b3c4a5";
    char s2[256];
    std::copy_if(s1.begin(), s1.end(), s2, [](char c){return c!='a';});
    std::cout << s2 << std::endl;
    return 0;
}

3
string RemoveChar(string str, char c) 
{
   string result;
   for (size_t i = 0; i < str.size(); i++) 
   {
          char currentChar = str[i];
          if (currentChar != c)
              result += currentChar;
   }
       return result;
}

Voilà comment je l'ai fait.

Ou vous pouvez faire comme Antoine l'a mentionné:

Voir cette question qui répond au même problème. Dans ton cas:

#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

1

Ce code supprime la répétition des caractères, c'est-à-dire que si l'entrée est aaabbcc alors la sortie sera abc.

cin >> s;
ans = "";
ans += s[0];
for(int i = 1;i < s.length();++i)
if(s[i] != s[i-1])
    ans += s[i];
cout << ans << endl;

1

Au cas où vous auriez un predicateet / ou un non vide outputà remplir avec la chaîne filtrée, je considérerais:

output.reserve(str.size() + output.size());  
std::copy_if(str.cbegin(), 
             str.cend(), 
             std::back_inserter(output), 
             predicate});

Dans la question d'origine, le prédicat est [](char c){return c != 'a';}


0

Sur la base d'autres réponses, voici un autre exemple où j'ai supprimé tous les caractères spéciaux dans une chaîne donnée:

#include <iostream>
#include <string>
#include <algorithm>

std::string chars(".,?!.:;_,!'\"-");

int main(int argc, char const *argv){

  std::string input("oi?");
  std::string output = eraseSpecialChars(input);   

 return 0;
}




std::string eraseSpecialChars(std::string str){

std::string newStr;
    newStr.assign(str);  

    for(int i = 0; i < str.length(); i++){
        for(int  j = 0; j < chars.length(); j++ ){
            if(str.at(i) == chars.at(j)){
                char c = str.at(i);
                newStr.erase(std::remove(newStr.begin(), newStr.end(), c), newStr.end());
            }
        }

    }      

return newStr; 
}

Entrée vs sortie:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Je suppose que la méthode std: remove fonctionne mais cela posait un problème de compatibilité avec les includes donc j'ai fini par écrire cette petite fonction:

string removeCharsFromString(const string str, char* charsToRemove )
{
    char c[str.length()+1]; // + terminating char
    const char *p = str.c_str();
    unsigned int z=0, size = str.length();
    unsigned int x;
    bool rem=false;

    for(x=0; x<size; x++)
    {
        rem = false;
        for (unsigned int i = 0; charsToRemove[i] != 0; i++)
        {
            if (charsToRemove[i] == p[x])
            {
                rem = true;
                break;
            }
        }
        if (rem == false) c[z++] = p[x];
    }

    c[z] = '\0';
    return string(c);
}

Utilisez simplement comme

myString = removeCharsFromString (maString, "abc \ r");

et il supprimera toutes les occurrences de la liste de caractères donnée.

Cela peut également être un peu plus efficace car la boucle revient après la première correspondance, nous faisons donc moins de comparaison.


1
Vous devinez bien. Plutôt que d'écrire le vôtre, mieux vaut découvrir pourquoi vous ne pouvez pas utiliser les en-têtes C ++ standard.
xtofl

Eh bien, c'est une opinion personnelle xtofl, ce n'est pas toujours bon d'utiliser le 3ème code, vous ne savez en fait pas ce qu'il fait ni les performances plutôt que d'écrire ce dont vous avez spécifiquement besoin.
Damien

1
Je comprends ce que tu veux dire. C'est l'humilité qui me pousse à choisir la version qui a été revue, testée, optimisée par des rédacteurs de bibliothèques professionnels à plein temps, plutôt que la mienne. La bibliothèque standard peut être considérée comme une connaissance requise: ses fonctions ainsi que sa complexité d'exécution.
xtofl

À part les chaînes, c'est une solution C à un problème C ++. Je ne pense pas que cela aurait dû être rejeté.
Owl

-1

Voici comment je fais:

std::string removeAll(std::string str, char c) {
    size_t offset = 0;
    size_t size = str.size();

    size_t i = 0;
    while (i < size - offset) {
        if (str[i + offset] == c) {
            offset++;
        }

        if (offset != 0) {
            str[i] = str[i + offset];
        }

        i++;
    }

    str.resize(size - offset);
    return str;
}

Fondamentalement, chaque fois que je trouve un caractère donné, j'avance le décalage et je déplace le caractère vers l'index correct. Je ne sais pas si c'est correct ou efficace, je commence (encore une fois) au C ++ et j'apprécierais toute contribution à ce sujet.


4
En repensant à cette question 4 mois plus tard, je ne sais vraiment pas pourquoi je n'ai pas utilisé std :: erase ou std :: replace.
Ricardo Pieper

-3
#include <string>
#include <algorithm>
std::string str = "YourString";
char chars[] = {'Y', 'S'};
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());

Supprime les majuscules Y et S de str, laissant "ourtring".

Notez qu'il removes'agit d'un algorithme et que l'en-tête doit être <algorithm>inclus.


ouais, je pense qu'il y a une boucle implicite sur les caractères de tableau qu'il a laissés de côté
RichardPlunkett
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.