Bagaimana cara menghapus karakter tertentu dari string di C ++?

96

Misalnya saya meminta pengguna memasukkan nomor telepon.

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

Saya ingin menghapus karakter "(", ")", dan "-" dari string. Saya telah melihat string hapus, temukan dan ganti fungsi namun saya hanya melihat bahwa mereka beroperasi berdasarkan posisi.

Apakah ada fungsi string yang dapat saya gunakan untuk meneruskan karakter, "(" misalnya, dan apakah fungsi tersebut menghapus semua instance dalam string?

SD.
sumber

Jawaban:

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;

Untuk digunakan sebagai fungsi :

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
sumber
4
Bagaimana cara kerjanya? Bukankah menggunakan double negative untuk menghapus dan menghapus? Bagi saya ini berbunyi: "hapus karakter yang berada di posisi di mana () - tidak." Dan karena masing-masing dilakukan pada satu waktu, bukankah seharusnya itu menghapus SEMUA karakter? Saya telah membaca dokumentasi tentang kedua fungsi tersebut, dan ini tidak masuk akal bagi saya. cplusplus.com/reference/algorithm/remove cplusplus.com/reference/string/string/erase
Brent
@Brent std :: remove () TIDAK akan menghapus karakter valid apa pun dari string, ini hanya memindahkan karakter valid bersama-sama.
lk_vc
20
@Brent dan pembaca masa depan, ini adalah idiom Hapus-hapus . Singkatnya, std::removememindahkan item yang tidak dihapus ke depan vektor dan mengembalikan iterator yang menunjuk tepat di luar item terakhir yang tidak dihapus. Kemudian std::erasepotong vektor dari iterator itu ke akhir.
chwarr
1
Untuk benar-benar C ++ versi saya pikir kita harus menggunakan string chars("()-");dan kemudian menggunakan .length()metode untuk mendapatkan panjang dan .at(i)metode untuk mengakses karakter :) Functionized biola - ideone.com/tAZt5I
jave.web
2
Untuk digunakan sebagai fungsi: ideone.com/XOROjq - kegunaan<iostream> <algorithm> <cstring>
jave.web
36

Saya ingin menghapus karakter "(", ")", dan "-" dari string.

Anda dapat menggunakan std::remove_if()algoritme untuk menghapus hanya karakter yang Anda tentukan:

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

The std::remove_if()algoritma membutuhkan sesuatu yang disebut predikat, yang dapat menjadi pointer fungsi seperti potongan di atas.

Anda juga dapat mengirimkan objek fungsi (objek yang membebani ()operator pemanggil fungsi ). Ini memungkinkan kami membuat solusi yang lebih umum:

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

Anda dapat menentukan karakter apa yang akan dihapus dengan "()- "string. Dalam contoh di atas saya menambahkan spasi sehingga spasi dihapus serta tanda kurung dan tanda hubung.

In silico
sumber
Anda juga bisa menggunakanispunct(int c)
MSalters
Implementasi yang sangat baik. Metode ini bekerja dengan sempurna dan memiliki banyak ruang untuk dinamika selanjutnya. Terima kasih atas tanggapannya. MSalters, saya juga akan mencari fungsi ispunct (int c) dan melaporkan kembali pekerjaan saya.
SD.
12

remove_if () telah disebutkan. Namun, dengan C ++ 0x, Anda dapat menentukan predikatnya dengan lambda.

Di bawah ini adalah contohnya dengan 3 cara berbeda untuk melakukan pemfilteran. Versi "copy" dari fungsi-fungsi tersebut juga disertakan untuk kasus-kasus ketika Anda bekerja dengan sebuah const atau tidak ingin mengubah aslinya.

#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;
}
Bayangan2531
sumber
Alih-alih const char & c, saya seharusnya benar-benar menggunakan string const :: value_type &. Tapi, itu bukan masalah besar dalam kasus ini.
Shadow2531
1
Ini adalah implementasi yang sangat menyeluruh. Saya menghargainya dan akan menggunakan implementasi ini juga.
SD.
8

Berikut adalah solusi berbeda untuk siapa pun yang tertarik. Ini menggunakan rentang For baru di 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
sumber
1
(1) str2inisialisasi tidak diperlukan. (2) str = std::move(str2)akan lebih efisien.
Ajay
6

Saya khawatir tidak ada anggota seperti itu untuk std :: string, tetapi Anda dapat dengan mudah memprogram fungsi semacam itu. Ini mungkin bukan solusi tercepat, tetapi ini sudah cukup:

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: Membaca jawaban di bawah ini, saya memahaminya secara lebih umum, tidak hanya untuk mendeteksi digit. Solusi di atas akan menghilangkan setiap karakter yang diteruskan dalam string argumen kedua. Sebagai contoh:

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

Akan menghasilkan

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

Catatan: Mungkin Anda perlu menulis ptr_fun<int, int>daripada sederhanaptr_fun

Oleg Svechkarenko
sumber
bagaimana ini bukan jawaban yang dipilih?
pengguna3240688
@ user3240688 Perhatikan bahwa std :: ptr_fun tidak digunakan lagi di C ++ 11 dan akan dihapus di C ++ 17 dan std :: not1 tidak digunakan lagi di C ++ 17. Anda bisa menggunakan std::crefatau std::function(atau lambda).
Roi Danton
3

Ya, Anda dapat menggunakan fungsi isdigit () untuk memeriksa digit :)

Ini dia:

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

Semoga membantu :)

Vern
sumber
Ini dapat dimodifikasi untuk menghapus elemen yang mengembalikan nilai salah. Terima kasih.
SD.
3

boost::is_any_of

Strip untuk semua karakter dari satu string yang muncul di string lain yang diberikan:

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

Diuji di Ubuntu 16.04, Boost 1.58.

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

Jika Anda memiliki akses ke kompiler yang mendukung template variadic, Anda dapat menggunakan ini:

#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;
}
Timesquare
sumber
1

Berikut alternatif lain:

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

Bekerja dengan std :: string dan std :: wstring

Jem
sumber
1

Saya baru, tetapi beberapa jawaban di atas sangat rumit, jadi inilah alternatifnya.

CATATAN: Selama 0-9 bersebelahan (yang harus sesuai dengan standar), ini harus menyaring semua karakter lain kecuali angka dan ''. Mengetahui 0-9 harus bersebelahan dan char benar-benar int, kita dapat melakukan hal di bawah ini.

EDIT: Saya tidak melihat poster menginginkan ruang juga, jadi saya mengubahnya ...

#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 bawah ini untuk memfilter karakter yang diberikan.

#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;
}
Hanya lelah
sumber
Itu tidak melakukan apa yang diinginkan OP; itu menghapus spasi juga.
Andrew Barber
1

Menggunakan std :: wstring dan wchar_t (membutuhkan header Unicode ):

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

... penginisialisasi jarak statis mewah berikutnya; tidak perlu mengatur badChars2 dengan cara yang sama persis. Itu berlebihan; lebih akademis dari apa pun:

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

Lambda sederhana dan ringkas:

  1. Menggunakan telepon dalam daftar tangkapan lambda.
  2. Menggunakan idiom Hapus-hapus
  3. Menghapus semua karakter buruk dari ponsel

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

Keluaran: "555 5555555"

Darrin
sumber
1

Bagi Anda yang lebih suka gaya pengkodean lambda yang lebih ringkas, lebih mudah dibaca ...

Contoh ini menghapus semua karakter non-alfanumerik dan spasi dari string lebar. Anda dapat mencampurnya dengan salah satu fungsi pembantu ctype.h lainnya untuk menghapus pengujian berbasis karakter yang tampak rumit.

(Saya tidak yakin bagaimana fungsi ini akan menangani bahasa CJK, jadi berjalanlah dengan lembut ke sana.)

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

Lihat jika Anda tidak menganggap ini lebih mudah untuk dipahami daripada loop C / C ++ untuk / iterator yang berisik:

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

hasil newLabel setelah menjalankan kode ini: " 1ReplenMoveRPMV "

Ini hanya akademis, karena jelas akan lebih tepat, ringkas dan efisien untuk menggabungkan logika 'if' dari lambda0 (first for_each ) ke dalam lambda1 tunggal (kedua for_each ), jika Anda telah menetapkan karakter mana yang menjadi "badChars" .

Darrin
sumber
Penghargaan untuk jawaban @Eric Z karena menyebutkan dan menggunakan idiom Hapus-hapus yang praktis. en.wikipedia.org/wiki/Erase-remove_idiom
Darrin
0

Banyak jawaban bagus, berikut adalah cara lain untuk membersihkan rangkaian angka, tidak menghapus karakter tetapi dengan memindahkan angka keluar.

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