Jak usunąć niektóre znaki z ciągu znaków w C++?

Na przykład mam użytkownika wprowadzającego numer telefonu.

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

Chcę usunąć znaki " ( " ,") " i " - " z łańcucha. Spojrzałem na ciąg Usuń, znajdź i zamień funkcje jednak widzę tylko, że działają one na podstawie pozycji.

Czy istnieje funkcja łańcuchowa, której mogę użyć, aby przekazać znak, " ("na przykład, i usunąć wszystkie instancje w łańcuchu?

14 answers

   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;

Do użycia jako Funkcja :

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, "()-" );
 142
Author: Eric Z,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-02 05:47:16

Chcę usunąć " ( " ,") " i "-" znaki z ciągu znaków.

Możesz użyć algorytmu std::remove_if(), aby usunąć tylko znaki, które podasz:

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

Algorytm std::remove_if() wymaga czegoś o nazwie predykat, który może być wskaźnikiem funkcji, takim jak powyższy fragment.

Można również przekazać obiekt funkcji (obiekt, który przeciąża wywołanie funkcji () operator). Dzięki temu możemy stworzyć jeszcze bardziej ogólne rozwiązanie:

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

Możesz określić, które znaki należy usunąć za pomocą ciągu "()- ". W powyższym przykładzie dodałem spację, aby spacje zostały usunięte, a także nawiasy i myślniki.

 38
Author: In silico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-05 02:01:51

Remove_if() zostało już wspomniane. Ale, w C++0x, można określić predykat dla niego z lambda zamiast.

Poniżej znajduje się przykład tego z 3 różnymi sposobami filtrowania. "Kopiuj" wersje funkcji są również włączone w przypadku, gdy pracujesz z const lub nie chcesz modyfikować oryginału.

#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
Author: Shadow2531,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-05 04:49:47

Oto inne rozwiązanie dla wszystkich zainteresowanych. Używa nowego zakresu w 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
Author: ashwin911,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-07 15:21:46

Obawiam się, że nie ma takiego członka dla std::string, ale można łatwo zaprogramować tego typu funkcje. Może nie jest to najszybsze rozwiązanie, ale wystarczyłoby:

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: czytając odpowiedź poniżej, zrozumiałem, że jest ona bardziej ogólna, nie tylko do wykrywania cyfr. Powyższe rozwiązanie pominie każdy znak przekazywany w drugim łańcuchu argumentów. Na przykład:

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

Spowoduje

99999876543.87
 6
Author: StormByte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-05 01:23:38
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());

Uwaga: to jest posible trzeba napisać ptr_fun<int, int> a nie proste ptr_fun

 3
Author: Oleg Svechkarenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 23:13:28

Tak, możesz użyć funkcji isdigit() do sprawdzenia cyfr :)

Proszę bardzo:

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

Mam nadzieję, że pomoże:)

 3
Author: Vern,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-05 07:56:11

boost::is_any_of

Pasek dla wszystkich znaków z jednego łańcucha, które pojawiają się w innym podanym łańcuchu:

#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"));
}
Testowane w Ubuntu 16.04, Boost 1.58.
 3
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-05 08:57:08

Jeśli masz dostęp do kompilatora, który obsługuje różne szablony, możesz użyć tego:

#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
Author: Timesquare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-05 03:07:13

Oto kolejna alternatywa:

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

Działa z std::string i STD:: wstring

 1
Author: Jem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 02:34:39

Jestem nowy, ale niektóre z powyższych odpowiedzi są szalenie skomplikowane, więc oto alternatywa.

Uwaga: dopóki 0-9 są sąsiadujące ze sobą (które powinny być zgodne ze standardem), powinno to odfiltrować wszystkie inne znaki oprócz cyfr i ' '. Wiedząc, że 0-9 powinno być sąsiadujące ze sobą, a znak jest tak naprawdę int, możemy wykonać poniższe czynności.

EDIT: nie zauważyłem, że plakat też chciał spacji, więc go zmieniłem...

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

Poniżej znajduje się filtrowanie podanych znaków.

#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
Author: JustTired,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-19 23:56:55

Using std::wstring and wchar_t (requires theUnicode header):

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

...fancy static range initializer next; nie trzeba ustawiać badChars2 dokładnie w ten sam sposób. To przesada; bardziej akademickie niż cokolwiek innego:

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

Proste, zwięzłe lambda:

  1. używa telefonu na liście przechwytywania lambda.
  2. Uses Erase-remove idiom
  3. Usuwa wszystkie złe znaki z telefonu

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

Wyjście: "555 5555555"

 1
Author: Darrin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-09 17:23:43

Dla tych z Was, którzy preferują bardziej zwięzły, łatwiejszy do odczytania styl kodowania lambda...

Ten przykład usuwa wszystkie Nie alfanumeryczne i białe znaki spacji z szerokiego ciągu znaków. Możesz go zmieszać z dowolnym innym ctype.h funkcje pomocnicze do usuwania złożonych testów opartych na znakach.

(nie jestem pewien, jak te funkcje poradziłyby sobie z językami CJK, więc idź cicho.)

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

Zobacz, czy nie jest to łatwiejsze do zrozumienia niż głośne C / C++ pętle for / 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());
});

Wyniki NewLabel po uruchomieniu tego kodu: "1replenmoverpmv "

Jest to po prostu akademickie, ponieważ wyraźnie byłoby bardziej precyzyjne, zwięzłe i skuteczne połączenie logiki " if " z lambda0 (first for_each) w pojedynczą lambda1 (second for_each), Jeśli już ustaliłeś, które znaki są "badChars".

 1
Author: Darrin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-09 17:47:40

Wiele dobrych odpowiedzi, tutaj jest inny sposób, aby oczyścić ciąg liczb, nie jest usuwanie znaków, ale przez przeniesienie liczb.

string str("(555) 555-5555"), clean;
for (char c : str)
    if (c >= 48 and c <= 57)
        clean.push_back(c);
 0
Author: Patricio Rossi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-08 02:39:56