Come rimuovere determinati caratteri da una stringa in C ++?


96

Ad esempio, un utente ha inserito un numero di telefono.

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

Desidero rimuovere i caratteri "(", ")" e "-" dalla stringa. Ho esaminato le funzioni di rimozione, ricerca e sostituzione della stringa, tuttavia vedo solo che funzionano in base alla posizione.

Esiste una funzione stringa che posso utilizzare per passare un carattere, "(" ad esempio, e fare in modo che rimuova tutte le istanze all'interno di una stringa?

Risposte:


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

Da utilizzare come funzione :

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, "()-" );

4
Come funziona? Non è un doppio negativo usare cancella e rimuovi? Per me questo dice: "cancella i caratteri che si trovano nelle posizioni dove () - non lo sono." E poiché ognuno viene eseguito alla volta, non dovrebbe rimuovere TUTTI i caratteri? Ho letto la documentazione su entrambe le funzioni e questo non ha senso per me. cplusplus.com/reference/algorithm/remove cplusplus.com/reference/string/string/erase
Brent

@Brent std :: remove () NON rimuoverà alcun carattere valido dalla stringa, sposta solo i caratteri validi insieme.
lk_vc

20
@Brent e futuri lettori, questo è l' idioma cancella-rimuovi . In breve, std::removesposta gli elementi non rimossi in primo piano nel vettore e restituisce un iteratore che punta appena oltre l'ultimo elemento non rimosso. Quindi std::erasetaglia il vettore da quell'iteratore alla fine.
chwarr

1
Per la versione davvero C ++ penso che dovremmo usare string chars("()-");e quindi usare il .length()metodo per ottenere la lunghezza e il .at(i)metodo per accedere ai caratteri :) Violino
jave.web

2
Per utilizzare come funzione: ideone.com/XOROjq - utilizza<iostream> <algorithm> <cstring>
jave.web

36

Desidero rimuovere i caratteri "(", ")" e "-" dalla stringa.

È possibile utilizzare l' std::remove_if()algoritmo per rimuovere solo i caratteri specificati:

#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' std::remove_if()algoritmo richiede qualcosa chiamato predicato, che può essere un puntatore a funzione come lo snippet sopra.

È inoltre possibile passare un oggetto funzione (un oggetto che sovraccarica l' ()operatore di chiamata di funzione ). Questo ci permette di creare una soluzione ancora più generale:

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

È possibile specificare quali caratteri rimuovere con la "()- "stringa. Nell'esempio sopra ho aggiunto uno spazio in modo che gli spazi vengano rimossi così come le parentesi ei trattini.


Puoi anche usareispunct(int c)
MSalters

Ottima realizzazione. Questo metodo ha funzionato perfettamente e ha molto spazio per ulteriori dinamiche. Grazie per la risposta. MSalters, cercherò anche la funzione ispunct (int c) e riferirò sul mio funzionamento.
SD.

12

remove_if () è già stato menzionato. Ma, con C ++ 0x, puoi specificare il predicato con un lambda invece.

Di seguito è riportato un esempio di ciò con 3 diversi modi di eseguire il filtraggio. Le versioni "copia" delle funzioni sono incluse anche per i casi in cui si lavora con un const o non si desidera modificare l'originale.

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

Invece di const char & c, avrei dovuto davvero usare const string :: value_type &. Ma non è un grosso problema in questo caso.
Shadow2531

1
Questa è un'implementazione molto completa. Lo apprezzo e userò anche questa implementazione.
SD.

8

Ecco una soluzione diversa per chiunque sia interessato. Utilizza la nuova gamma For in 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
(1) str2non è richiesta l'inizializzazione. (2) str = std::move(str2)sarebbe più efficiente.
Ajay

6

Temo che non esista un membro simile per std :: string, ma puoi facilmente programmare quel tipo di funzioni. Potrebbe non essere la soluzione più veloce ma sarebbe sufficiente:

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: leggendo la risposta di seguito, ho capito che è più generale, non solo per rilevare la cifra. La soluzione precedente ometterà ogni carattere passato nella seconda stringa dell'argomento. Per esempio:

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

Risulterà in

99999876543.87

3
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());

Nota: è possibile che tu abbia bisogno di scrivere ptr_fun<int, int>piuttosto che sempliceptr_fun


come è questa non la risposta selezionata?
user3240688

@ user3240688 Nota che std :: ptr_fun è deprecato in C ++ 11 e verrà rimosso in C ++ 17 e std :: not1 è deprecato in C ++ 17. Potresti usare std::crefo std::function(o lambda).
Roi Danton

3

Sì, puoi utilizzare la funzione isdigit () per verificare la presenza di cifre :)

Ecco qui:

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

Spero che sia d'aiuto :)


Questo può essere modificato per rimuovere l'elemento che restituisce false. Grazie.
SD.

3

boost::is_any_of

Elimina tutti i caratteri da una stringa che appare in un'altra stringa data:

#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"));
}

Testato in Ubuntu 16.04, Boost 1.58.


2

Se hai accesso a un compilatore che supporta modelli variadici, puoi utilizzare questo:

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

1

Ecco un'altra alternativa:

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, "()-");

Funziona con std :: string e std :: wstring


1

Sono nuovo, ma alcune delle risposte sopra sono incredibilmente complicate, quindi ecco un'alternativa.

NOTA: Finché 0-9 sono contigui (che dovrebbero essere secondo lo standard), questo dovrebbe filtrare tutti gli altri caratteri tranne i numeri e ''. Sapendo che 0-9 dovrebbe essere contiguo e un carattere è davvero un int, possiamo fare quanto segue.

EDIT: Non ho notato che anche il poster voleva spazi, quindi l'ho modificato ...

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

Di seguito è necessario filtrare i caratteri forniti.

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

Questo non fa quello che voleva l'OP; cancella anche gli spazi.
Andrew Barber

1

Utilizzando std :: wstring e wchar_t (richiede l' intestazione Unicode ):

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

... successivo inizializzatore di intervallo statico fantasia; non è necessario impostare badChars2 esattamente allo stesso modo. È eccessivo; più accademico che altro:

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

Lambda semplice e conciso:

  1. Utilizza il telefono nell'elenco di acquisizione lambda.
  2. Utilizza il linguaggio Cancella-rimuovi
  3. Rimuove tutti i caratteri cattivi dal telefono

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

Uscita: "555 5555555"


1

Per quelli di voi che preferiscono uno stile di codifica lambda più conciso e più facile da leggere ...

Questo esempio rimuove tutti i caratteri non alfanumerici e gli spazi vuoti da una stringa ampia. Puoi mescolarlo con una qualsiasi delle altre funzioni di supporto di ctype.h per rimuovere test basati sui caratteri dall'aspetto complesso.

(Non sono sicuro di come queste funzioni gestiscano i linguaggi CJK, quindi cammina dolcemente lì.)

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

Vedi se non trovi questo più facile da capire rispetto ai rumorosi C / C ++ per i cicli / 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());
});

risultati newLabel dopo aver eseguito questo codice: " 1ReplenMoveRPMV "

Questo è solo accademico, poiché sarebbe chiaramente più preciso, conciso ed efficiente combinare la logica 'if' da lambda0 (primo for_each ) nel singolo lambda1 (secondo for_each ), se hai già stabilito quali caratteri sono i "badChars" .


Ringraziamo la risposta di @Eric Z per aver menzionato e utilizzato il pratico linguaggio Cancella-rimuovi. en.wikipedia.org/wiki/Erase-remove_idiom
Darrin

0

Molte buone risposte, ecco un altro modo per ripulire una stringa di numeri, non è l'eliminazione dei caratteri ma spostando i numeri fuori.

string str("(555) 555-5555"), clean;
for (char c : str)
    if (c >= 48 and c <= 57)
        clean.push_back(c);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.