Wie entferne ich bestimmte Zeichen aus einer Zeichenfolge in C ++?

96

Zum Beispiel muss ein Benutzer eine Telefonnummer eingeben.

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

Ich möchte die Zeichen "(", ")" und "-" aus der Zeichenfolge entfernen. Ich habe mir die Funktionen zum Entfernen, Suchen und Ersetzen von Zeichenfolgen angesehen, sehe jedoch nur, dass sie basierend auf der Position funktionieren.

Gibt es eine Zeichenfolgenfunktion, mit der ich ein Zeichen "(") übergeben und alle Instanzen innerhalb einer Zeichenfolge entfernen lassen kann?

SD.
quelle

Antworten:

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;

So verwenden Sie als Funktion :

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, "()-" );
Eric Z.
quelle
4
Wie funktioniert das? Ist es nicht ein doppeltes Negativ, Löschen und Entfernen zu verwenden? Für mich lautet dies: "Lösche die Zeichen, die sich an Positionen befinden, an denen () - nicht sind." Und da jedes einzeln ausgeführt wird, sollte es nicht ALLE Zeichen entfernen? Ich habe die Dokumentation zu beiden Funktionen gelesen, und das macht für mich keinen Sinn. cplusplus.com/reference/algorithm/remove cplusplus.com/reference/string/string/erase
Brent
@Brent std :: remove () entfernt KEINE gültigen Zeichen aus der Zeichenfolge, sondern verschiebt nur gültige Zeichen zusammen.
lk_vc
20
@Brent und zukünftige Leser, dies ist die Redewendung zum Löschen und Entfernen . Verschiebt std::removedie nicht entfernten Elemente kurz an die Vorderseite des Vektors und gibt einen Iterator zurück, der direkt hinter das letzte nicht entfernte Element zeigt. Dann std::eraseschneidet der Vektor von diesem Iterator bis zum Ende.
Chwarr
1
Für wirklich C ++ Version denke ich, wir sollten string chars("()-");und dann .length()Methode verwenden, um die Länge und .at(i)Methode zu erhalten, um auf die Zeichen zuzugreifen :) Funktionierte Geige - ideone.com/tAZt5I
jave.web
2
Als Funktion zu verwenden: ideone.com/XOROjq - verwendet<iostream> <algorithm> <cstring>
jave.web
36

Ich möchte die Zeichen "(", ")" und "-" aus der Zeichenfolge entfernen.

Mit dem std::remove_if()Algorithmus können Sie nur die von Ihnen angegebenen Zeichen entfernen:

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

Der std::remove_if()Algorithmus erfordert ein sogenanntes Prädikat, das ein Funktionszeiger wie das obige Snippet sein kann.

Sie können auch ein Funktionsobjekt übergeben (ein Objekt, das den Funktionsaufrufoperator überlastet ()). Dies ermöglicht es uns, eine noch allgemeinere Lösung zu erstellen:

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

Sie können angeben, welche Zeichen mit der "()- "Zeichenfolge entfernt werden sollen. Im obigen Beispiel habe ich ein Leerzeichen hinzugefügt, damit Leerzeichen sowie Klammern und Bindestriche entfernt werden.

In silico
quelle
Sie könnten auch verwendenispunct(int c)
MSalters
Hervorragende Umsetzung. Diese Methode hat einwandfrei funktioniert und bietet viel Raum für weitere Dynamik. Danke für die Antwort. MSalters, ich werde auch die Funktion ispunct (int c) nachschlagen und über meine Arbeit berichten.
SD.
12

remove_if () wurde bereits erwähnt. Mit C ++ 0x können Sie das Prädikat dafür jedoch stattdessen mit einem Lambda angeben.

Unten finden Sie ein Beispiel dafür mit drei verschiedenen Arten der Filterung. "Kopier" -Versionen der Funktionen sind auch für Fälle enthalten, in denen Sie mit einer Konstante arbeiten oder das Original nicht ändern möchten.

#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;
}
Shadow2531
quelle
Anstelle von const char & c hätte ich wirklich const string :: value_type & verwenden sollen. Aber in diesem Fall ist es keine große Sache.
Shadow2531
1
Dies ist eine sehr gründliche Implementierung. Ich weiß das zu schätzen und werde diese Implementierung auch nutzen.
SD.
8

Hier ist eine andere Lösung für alle Interessierten. Es verwendet den neuen For-Bereich 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;
ashwin911
quelle
1
(1) Eine str2Initialisierung ist nicht erforderlich. (2) str = std::move(str2)wäre effizienter.
Ajay
6

Ich fürchte, es gibt kein solches Mitglied für std :: string, aber Sie können diese Art von Funktionen einfach programmieren. Es ist vielleicht nicht die schnellste Lösung, aber dies würde ausreichen:

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: Als ich die Antwort unten las, verstand ich, dass sie allgemeiner ist und nicht nur Ziffern erkennt. Bei der obigen Lösung wird jedes in der zweiten Argumentzeichenfolge übergebene Zeichen weggelassen. Beispielsweise:

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

Wird darin enden, dass

99999876543.87
StormByte
quelle
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());

Hinweis: Möglicherweise müssen Sie ptr_fun<int, int>eher schreiben als einfachptr_fun

Oleg Svechkarenko
quelle
Wie ist das nicht die ausgewählte Antwort?
user3240688
@ user3240688 Beachten Sie, dass std :: ptr_fun in C ++ 11 veraltet ist und in C ++ 17 entfernt wird und std :: not1 in C ++ 17 veraltet ist. Sie könnten std::crefoder std::function(oder Lambdas) verwenden.
Roi Danton
3

Ja, Sie können die Funktion isdigit () verwenden, um nach Ziffern zu suchen :)

Bitte schön:

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

Ich hoffe es hilft :)

Vern
quelle
Dies kann geändert werden, um das Element zu entfernen, das false zurückgibt. Danke dir.
SD.
3

boost::is_any_of

Streifen für alle Zeichen aus einer Zeichenfolge, die in einer anderen angegebenen Zeichenfolge erscheinen:

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

Getestet in Ubuntu 16.04, Boost 1.58.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
2

Wenn Sie Zugriff auf einen Compiler haben, der verschiedene Vorlagen unterstützt, können Sie Folgendes verwenden:

#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;
}
Time Square
quelle
1

Hier ist noch eine andere 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, "()-");

Funktioniert mit std :: string und std :: wstring

Jem
quelle
1

Ich bin neu, aber einige der obigen Antworten sind wahnsinnig kompliziert. Hier ist eine Alternative.

HINWEIS: Solange 0-9 zusammenhängend sind (was dem Standard entsprechen sollte), sollten alle anderen Zeichen außer Zahlen und '' herausgefiltert werden. Zu wissen, dass 0-9 zusammenhängend sein sollte und ein Zeichen wirklich ein Int ist, können wir wie folgt tun.

EDIT: Ich habe nicht bemerkt, dass das Poster auch Leerzeichen wollte, also habe ich es geändert ...

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

Im Folgenden werden die angegebenen Zeichen gefiltert.

#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;
}
Einfach müde
quelle
Das macht nicht das, was das OP wollte; es löscht auch die Leerzeichen.
Andrew Barber
1

Verwenden von std :: wstring und wchar_t (erfordert den Unicode- Header):

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

... Lust auf einen statischen Bereichsinitialisierer als nächstes; Es ist nicht notwendig, badChars2 genau so einzurichten. Es ist übertrieben; akademischer als alles andere:

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

Einfaches, prägnantes Lambda:

  1. Verwendet Telefon in der Lambda-Erfassungsliste.
  2. Verwendet das Erase-Remove-Idiom
  3. Entfernt alle schlechten Zeichen vom Telefon

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

Ausgabe: "555 5555555"

Darrin
quelle
1

Für diejenigen unter Ihnen, die einen prägnanteren, leichter zu lesenden Lambda-Codierungsstil bevorzugen ...

In diesem Beispiel werden alle nicht alphanumerischen Zeichen und Leerzeichen aus einer breiten Zeichenfolge entfernt. Sie können es mit jedem anderen ctype.h verwechseln , um komplex aussehende Tests zu entfernen.

(Ich bin mir nicht sicher, wie diese Funktionen mit CJK-Sprachen umgehen würden. Gehen Sie also leise dorthin.)

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

Sehen Sie, ob Sie dies nicht einfacher zu verstehen finden als verrauschte C / C ++ for / iterator-Schleifen:

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

newLabel ergibt sich nach Ausführung dieses Codes: " 1ReplenMoveRPMV "

Dies ist nur akademisch, da es eindeutig präziser, prägnanter und effizienter wäre, die 'if'-Logik von lambda0 (first for_each ) in das einzelne lambda1 (second for_each ) zu kombinieren , wenn Sie bereits festgestellt haben, welche Zeichen die "badChars" sind. .

Darrin
quelle
Dank an die Antwort von @Eric Z für die Erwähnung und Verwendung des praktischen Erase-Remove-Idioms. en.wikipedia.org/wiki/Erase-remove_idiom
Darrin
0

Viele gute Antworten, hier ist eine andere Möglichkeit, eine Reihe von Zahlen zu bereinigen, besteht nicht darin, Zeichen zu löschen, sondern die Zahlen zu verschieben.

string str("(555) 555-5555"), clean;
for (char c : str)
    if (c >= 48 and c <= 57)
        clean.push_back(c);
Patricio Rossi
quelle