如何在 C + + 中删除字符串中的某些字符?

例如,我有一个用户输入一个电话号码。

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

我想从字符串中删除“(”、“)”和“-”字符。我已经查看了字符串删除、查找和替换函数,但是我只看到它们根据位置进行操作。

有没有一个字符串函数,我可以用来传递一个字符,例如,“(”,并有它删除所有的实例在一个字符串?

310647 次浏览

Yes, you can use the isdigit() function to check for a digits :)

Here you go:

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

Hope it helps :)

   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;

To use as function:

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

I'm afraid there is no such a member for std::string, but you can easily program that kind of functions. It may not be the fastest solution but this would suffice:

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: Reading the answer below, I understood it to be more general, not only to detect digit. The above solution will omit every character passed in the second argument string. For example:

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

Will result in

99999876543.87

I want to remove the "(", ")", and "-" characters from the string.

You can use the std::remove_if() algorithm to remove only the characters you specify:

#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() algorithm requires something called a predicate, which can be a function pointer like the snippet above.

You can also pass a function object (an object that overloads the function call () operator). This allows us to create an even more general solution:

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

You can specify what characters to remove with the "()- " string. In the example above I added a space so that spaces are removed as well as parentheses and dashes.

If you have access to a compiler that supports variadic templates, you can use this:

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

remove_if() has already been mentioned. But, with C++0x, you can specify the predicate for it with a lambda instead.

Below is an example of that with 3 different ways of doing the filtering. "copy" versions of the functions are included too for cases when you're working with a const or don't want to modify the 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;
}

Here's yet another 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, "()-");

Works with std::string and std::wstring

I'm new, but some of the answers above are insanely complicated, so here's an alternative.

NOTE: As long as 0-9 are contiguous (which they should be according to the standard), this should filter out all other characters but numbers and ' '. Knowing 0-9 should be contiguous and a char is really an int, we can do the below.

EDIT: I didn't notice the poster wanted spaces too, so I altered it...

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

Below is to filter supplied characters.

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

Here is a different solution for anyone interested. It uses the new For range 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;
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: It's posible you need write ptr_fun<int, int> rather than simple ptr_fun

For those of you that prefer a more concise, easier to read lambda coding style...

This example removes all non-alphanumeric and white space characters from a wide string. You can mix it up with any of the other ctype.h helper functions to remove complex-looking character-based tests.

(I'm not sure how these functions would handle CJK languages, so walk softly there.)

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

See if you don't find this easier to understand than noisy C/C++ for/iterator loops:

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 results after running this code: "1ReplenMoveRPMV"

This is just academic, since it would clearly be more precise, concise and efficient to combine the 'if' logic from lambda0 (first for_each) into the single lambda1 (second for_each), if you have already established which characters are the "badChars".

Using std::wstring and wchar_t (requires the Unicode header):

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

...fancy static range initializer next; not necessary to setup badChars2 this exact same way. It's overkill; more academic than anything else:

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

Simple, concise lambda:

  1. Uses phone in the lambda capture list.
  2. Uses Erase-remove idiom
  3. Removes all bad characters from 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;
    

Output: "555 5555555"

boost::is_any_of

Strip for all characters from one string that appear in another given string:

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

Tested in Ubuntu 16.04, Boost 1.58.

Lot of good answers, here is another way to clean up a string of numbers, is not deleting chars but by moving the numbers out.

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

From C++20, you can use erase/erase_if for std::basic_string, which is basically a convenience wrapper for the erase-remove idiom

std::erase(phone, '(');

and

std::erase_if(phone, [](char x) {
return x == '(' or x == ')' or x == '-';
});

Note that these functions return the count of how many characters were erased as well.