105 votes

Comment supprimer certains caractères d'une chaîne de caractères en C++ ?

Par exemple, un utilisateur saisit un numéro de téléphone.

cout << "Enter phone number: ";
INPUT: (555) 555-5555
cin >> phone;

Je souhaite supprimer les caractères "(", ")" et "-" de la chaîne. J'ai examiné les fonctions de suppression, de recherche et de remplacement des chaînes de caractères, mais je constate qu'elles ne fonctionnent qu'en fonction de la position.

Existe-t-il une fonction de chaîne que je puisse utiliser pour passer un caractère, "(" par exemple, et faire en sorte qu'il supprime toutes les instances au sein d'une chaîne ?

145voto

Eric Z Points 7160
   string str("(555) 555-5555");

   char chars[] = "()-";

   for (unsigned int i = 0; i < strlen(chars); ++i)
   {
      // you need include <algorithm> to use general algorithms like std::remove()
      str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
   }

   // output: 555 5555555
   cout << str << endl;

A utiliser comme fonction :

void removeCharsFromString( string &str, char* charsToRemove ) {
   for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) {
      str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() );
   }
}
//example of usage:
removeCharsFromString( str, "()-" );

5 votes

Comment cela fonctionne-t-il ? N'est-ce pas une double négation que d'utiliser l'effacement et la suppression ? Pour moi, cela se lit comme suit : "effacer les caractères qui se trouvent à des endroits où les ()- ne se trouvent pas". Et comme on le fait à chaque fois, cela ne devrait-il pas effacer TOUS les caractères ? J'ai lu la documentation sur les deux fonctions, et cela n'a aucun sens pour moi. cplusplus.com/reference/algorithme/remove cplusplus.com/reference/string/string/erase

0 votes

@Brent std::remove() ne supprime PAS les caractères valides de la chaîne, il ne fait que déplacer les caractères valides les uns vers les autres.

21 votes

@Brent et les futurs lecteurs, c'est la Idée reçue d'effacer et de supprimer . En bref, std::remove déplace les éléments non retirés vers l'avant du vecteur et renvoie un itérateur pointant juste après le dernier élément non retiré. Dans ce cas std::erase coupe le vecteur de cet itérateur jusqu'à la fin.

40voto

In silico Points 30778

Je souhaite supprimer les caractères "(", ")" et "-". de la chaîne de caractères.

Vous pouvez utiliser le std::remove_if() pour ne supprimer que les caractères spécifiés :

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

bool IsParenthesesOrDash(char c)
{
    switch(c)
    {
    case '(':
    case ')':
    case '-':
        return true;
    default:
        return false;
    }
}

int main()
{
    std::string str("(555) 555-5555");
    str.erase(std::remove_if(str.begin(), str.end(), &IsParenthesesOrDash), str.end());
    std::cout << str << std::endl; // Expected output: 555 5555555
}

En std::remove_if() nécessite ce que l'on appelle un prédicat, qui peut être un pointeur de fonction comme dans l'extrait ci-dessus.

Vous pouvez également passer un fonction objet (un objet qui surcharge l'appel de fonction () ). Cela nous permet de créer une solution encore plus générale :

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

class IsChars
{
public:
    IsChars(const char* charsToRemove) : chars(charsToRemove) {};

    bool operator()(char c)
    {
        for(const char* testChar = chars; *testChar != 0; ++testChar)
        {
            if(*testChar == c) { return true; }
        }
        return false;
    }

private:
    const char* chars;
};

int main()
{
    std::string str("(555) 555-5555");
    str.erase(std::remove_if(str.begin(), str.end(), IsChars("()- ")), str.end());
    std::cout << str << std::endl; // Expected output: 5555555555
}

Vous pouvez spécifier les caractères à supprimer à l'aide de l'option "()- " chaîne de caractères. Dans l'exemple ci-dessus, j'ai ajouté un espace pour que les espaces soient supprimés ainsi que les parenthèses et les tirets.

0 votes

Vous pouvez également utiliser ispunct(int c)

0 votes

Excellente mise en œuvre. Cette méthode a parfaitement fonctionné et offre une grande marge de manœuvre pour une dynamique plus poussée. Je vous remercie pour votre réponse. MSalters, je vais également rechercher la fonction ispunct(int c) et rendre compte de mes travaux.

13voto

Shadow2531 Points 6726

La fonction remove_if() a déjà été mentionnée. Mais, avec C++0x, vous pouvez spécifier le prédicat avec une lambda à la place.

Vous trouverez ci-dessous un exemple de cette méthode avec trois façons différentes d'effectuer le filtrage. Les versions "copie" des fonctions sont également incluses pour les cas où vous travaillez avec une constante ou ne voulez pas modifier l'original.

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;

string& remove_chars(string& s, const string& chars) {
    s.erase(remove_if(s.begin(), s.end(), [&chars](const char& c) {
        return chars.find(c) != string::npos;
    }), s.end());
    return s;
}
string remove_chars_copy(string s, const string& chars) {
    return remove_chars(s, chars);
}

string& remove_nondigit(string& s) {
    s.erase(remove_if(s.begin(), s.end(), [](const char& c) {
        return !isdigit(c);
    }), s.end());
    return s;
}
string remove_nondigit_copy(string s) {
    return remove_nondigit(s);
}

string& remove_chars_if_not(string& s, const string& allowed) {
    s.erase(remove_if(s.begin(), s.end(), [&allowed](const char& c) {
        return allowed.find(c) == string::npos;
    }), s.end());
    return s;
}
string remove_chars_if_not_copy(string s, const string& allowed) {
    return remove_chars_if_not(s, allowed);
}

int main() {
    const string test1("(555) 555-5555");
    string test2(test1);
    string test3(test1);
    string test4(test1);
    cout << remove_chars_copy(test1, "()- ") << endl;
    cout << remove_chars(test2, "()- ") << endl;
    cout << remove_nondigit_copy(test1) << endl;
    cout << remove_nondigit(test3) << endl;
    cout << remove_chars_if_not_copy(test1, "0123456789") << endl;
    cout << remove_chars_if_not(test4, "0123456789") << endl;
}

0 votes

Au lieu de const char& c, j'aurais dû utiliser const string::value_type&. Mais ce n'est pas grave dans ce cas.

1 votes

Il s'agit d'une mise en œuvre très complète. Je l'apprécie et je l'utiliserai également.

9voto

ashwin911 Points 41

Voici une solution différente pour les personnes intéressées. Elle utilise la nouvelle plage For de c++11

string str("(555) 555-5555");
string str2="";

for (const auto c: str){

    if(!ispunct(c)){

        str2.push_back(c);
    }
}

str = str2;
//output: 555 5555555
cout<<str<<endl;

1 votes

(1) str2 l'initialisation n'est pas nécessaire. (2) str = std::move(str2) serait plus efficace.

7voto

StormByte Points 603

Je crains qu'un tel membre n'existe pas pour std::string, mais vous pouvez facilement programmer ce type de fonctions. Ce n'est peut-être pas la solution la plus rapide, mais elle est suffisante :

std::string RemoveChars(const std::string& source, const std::string& chars) {
   std::string result="";
   for (unsigned int i=0; i<source.length(); i++) {
      bool foundany=false;
      for (unsigned int j=0; j<chars.length() && !foundany; j++) {
         foundany=(source[i]==chars[j]);
      }
      if (!foundany) {
         result+=source[i];
      }
   }
   return result;
}

EDIT : En lisant la réponse ci-dessous, j'ai compris qu'elle était plus générale, et qu'elle ne concernait pas uniquement la détection des chiffres. La solution ci-dessus omettra tous les caractères passés dans la deuxième chaîne d'arguments. Par exemple :

std::string result=RemoveChars("(999)99-8765-43.87", "()-");

Il en résultera

99999876543.87

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