web-dev-qa-db-fra.com

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

Par exemple, je demande à un utilisateur d'entrer 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 de chaîne, mais je constate uniquement qu'elles fonctionnent en fonction de la position.

Existe-t-il une fonction de chaîne que je peux utiliser pour transmettre un caractère, "(" par exemple, et lui demander de supprimer toutes les occurrences d'une chaîne?

92
SD.
   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;

Pour 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, "()-" );
130
Eric Z

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

Vous pouvez utiliser l'algorithme std::remove_if() pour supprimer uniquement 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
}

L'algorithme std::remove_if() requiert un prédicat, qui peut être un pointeur de fonction comme l'extrait de code ci-dessus.

Vous pouvez également transmettre un objet function (un objet qui surcharge l'opérateur de 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 avec la chaîne "()- ". Dans l'exemple ci-dessus, j'ai ajouté un espace afin que les espaces soient supprimés, ainsi que les parenthèses et les tirets.

35
In silico

remove_if () a déjà été mentionné. Mais, avec C++ 0x, vous pouvez spécifier le prédicat correspondant avec un lambda.

Vous trouverez ci-dessous un exemple de cela avec 3 manières différentes de filtrer. Des versions "copier" des fonctions sont également incluses pour les cas où vous travaillez avec un const ou que vous 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;
}
12
Shadow2531

Voici une solution différente pour toute personne intéressée. Il utilise la nouvelle gamme For en 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;
8
ashwin911

J'ai bien peur qu'il n'y ait pas un tel membre pour std :: string, mais vous pouvez facilement programmer ce genre de fonctions. Ce n'est peut-être pas la solution la plus rapide mais cela suffirait:

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, pas seulement pour détecter un chiffre. La solution ci-dessus omettra tous les caractères passés dans la deuxième chaîne d'argument. Par exemple:

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

Aura pour résultat

99999876543.87
6
StormByte

boost::is_any_of

Bande pour tous les caractères d'une chaîne qui apparaissent dans une autre chaîne donnée:

_#include <cassert>

#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>

int main() {
    std::string str = "a_bc0_d";
    str.erase(boost::remove_if(str, boost::is_any_of("_0")), str.end());
    assert((str == "abcd"));
}
_

Testé dans Ubuntu 16.04, Boost 1.58.

using namespace std;


// c++03
string s = "(555) 555-5555";
s.erase(remove_if(s.begin(), s.end(), not1(ptr_fun(::isdigit))), s.end());

// c++11
s.erase(remove_if(s.begin(), s.end(), ptr_fun(::ispunct)), s.end());

Note: Il est possible que vous ayez besoin d'écrire ptr_fun<int, int> plutôt que de simple ptr_fun

4

Oui, vous pouvez utiliser la fonction isdigit () pour rechercher des chiffres :)

Voici:

#include <iostream>
#include <cctype>
#include <string.h>

using namespace std;

int main(){

  char *str = "(555) 555-5555";
  int len = strlen(str);

  for (int i=0; i<len; i++){
      if (isdigit(*(str+i))){
        cout << *(str+i);
      }
  }

  cout << endl;


return 0;   
}

J'espère que ça aide :)

3
Vern

Si vous avez accès à un compilateur qui prend en charge les modèles variadiques, vous pouvez utiliser ceci:

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

template<char ... CharacterList>
inline bool check_characters(char c) {
    char match_characters[sizeof...(CharacterList)] = { CharacterList... };
    for(int i = 0; i < sizeof...(CharacterList); ++i) {
        if(c == match_characters[i]) {
            return true;
        }
    }
    return false;
}

template<char ... CharacterList>
inline void strip_characters(std::string & str) {
    str.erase(std::remove_if(str.begin(), str.end(), &check_characters<CharacterList...>), str.end());
}

int main()
{
    std::string str("(555) 555-5555");
    strip_characters< '(',')','-' >(str);
    std::cout << str << std::endl;
}
2
Timesquare

Voici encore une autre alternative:

template<typename T>
void Remove( std::basic_string<T> & Str, const T * CharsToRemove )
{
    std::basic_string<T>::size_type pos = 0;
    while (( pos = Str.find_first_of( CharsToRemove, pos )) != std::basic_string<T>::npos )
    {
        Str.erase( pos, 1 ); 
    }
}

std::string a ("(555) 555-5555");
Remove( a, "()-");

Fonctionne avec std :: string et std :: wstring

1
Jem

Je suis nouveau, mais certaines des réponses ci-dessus sont incroyablement compliquées, alors voici une alternative.

REMARQUE: tant que 0 à 9 sont contigus (ce qui devrait être le cas selon la norme), ceci devrait filtrer tous les autres caractères sauf les chiffres et ''. Sachant que 0-9 devrait être contigu et qu'un caractère est vraiment un entier, nous pouvons faire le dessous.

EDIT: Je n'ai pas remarqué l'affiche aussi, je l'ai donc modifiée ...

#include <cstdio>
#include <cstring>

void numfilter(char * buff, const char * string)
{
  do
  { // According to standard, 0-9 should be contiguous in system int value.
    if ( (*string >= '0' && *string <= '9') || *string == ' ')
      *buff++ = *string;
  } while ( *++string );
  *buff++ = '\0'; // Null terminate
}

int main()
{
  const char *string = "(555) 555-5555";
  char buff[ strlen(string) + 1 ];

  numfilter(buff, string);
  printf("%s\n", buff);

return 0;
}

Ci-dessous est de filtrer les caractères fournis.

#include <cstdio>
#include <cstring>

void cfilter(char * buff, const char * string, const char * toks)
{
  const char * tmp;  // So we can keep toks pointer addr.
  do
  {
    tmp = toks;
    *buff++ = *string; // Assume it's correct and place it.
    do                 // I can't think of a faster way.
    {
      if (*string == *tmp)
      {
        buff--;  // Not correct, pull back and move on.
        break;
      }
    }while (*++tmp);
  }while (*++string);

  *buff++ = '\0';  // Null terminate
}

int main()
{
  char * string = "(555) 555-5555";
  char * toks = "()-";
  char buff[ strlen(string) + 1 ];

  cfilter(buff, string, toks);
  printf("%s\n", buff);

  return 0;
}
1
JustTired

Pour ceux qui préfèrent un style de codage lambda plus concis et plus facile à lire ...

Cet exemple supprime tous les caractères non alphanumériques et les espaces vides d'une chaîne large. Vous pouvez le mélanger avec n'importe laquelle des autres fonctions auxiliaires ctype.h pour supprimer les tests complexes basés sur des caractères.

(Je ne suis pas sûr de savoir comment ces fonctions géreraient les langues CJK, allez-y doucement.)

    // Boring C loops: 'for(int i=0;i<str.size();i++)' 
    // Boring C++ eqivalent: 'for(iterator iter=c.begin; iter != c.end; ++iter)'

Voyez si vous ne trouvez pas cela plus facile à comprendre que les boucles bruyantes C/C++ pour/iterator:

TSTRING label = _T("1.   Replen & Move  RPMV");
TSTRING newLabel = label;
set<TCHAR> badChars; // Use ispunct, isalpha, isdigit, et.al. (lambda version, with capture list parameter(s) example; handiest thing since sliced bread)
for_each(label.begin(), label.end(), [&badChars](TCHAR n){
    if (!isalpha(n) && !isdigit(n))
        badChars.insert(n);
});

for_each(badChars.begin(), badChars.end(), [&newLabel](TCHAR n){
    newLabel.erase(std::remove(newLabel.begin(), newLabel.end(), n), newLabel.end());
});

résultats newLabel après avoir exécuté ce code: " 1ReplenMoveRPMV "

Ceci est juste théorique, car il serait clairement plus précis, concis et efficace de combiner la logique du 'si' de lambda0 (premier pour_each ) dans le single lambda1 (second for_each ), si vous avez déjà établi quels caractères sont les "badChars".

1
Darrin

Utiliser std :: wstring et wchar_t (nécessite le Unicode en-tête):

//#include <tchar.h>
std::wstring phone(L"(555) 555-5555");

... fantaisie initialiseur de gamme statique suivant; pas nécessaire de configurer badChars2 de la même manière. C'est exagéré; plus académique qu'autre chose:

const wchar_t *tmp = L"()-"; 
const std::set<wchar_t> badChars2(tmp,tmp + sizeof(tmp)-1);

Lambda simple et concis:

  1. Utilise un téléphone dans la liste de capture lambda.
  2. Utilisations idiome Effacer-supprimer
  3. Supprime tous les caractères incorrects du téléphone

    for_each(badChars2.begin(), badChars2.end(), [&phone](wchar_t n){
         phone.erase(std::remove(phone.begin(), phone.end(), n), phone.end());
    });
    wcout << phone << endl;
    

Sortie: "555 5555555"

1
Darrin