How to remove certain characters from a string in C++?

C++StringCharacter

C++ Problem Overview


For example I have a user input a phone number.

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

I want to remove the "(", ")", and "-" characters from the string. I've looked at the string remove, find and replace functions however I only see that they operate based on position.

Is there a string function that I can use to pass a character, "(" for example, and have it remove all instances within a string?

C++ Solutions


Solution 1 - C++

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

Solution 2 - C++

> 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.

Solution 3 - C++

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

Solution 4 - C++

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;

Solution 5 - C++

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

Solution 6 - C++

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 :)

Solution 7 - C++

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

Solution 8 - C++

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.

Solution 9 - C++

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

Solution 10 - C++

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

Solution 11 - C++

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

Solution 12 - C++

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".

Solution 13 - C++

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"

Solution 14 - C++

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

Solution 15 - 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSD.View Question on Stackoverflow
Solution 1 - C++Eric ZView Answer on Stackoverflow
Solution 2 - C++In silicoView Answer on Stackoverflow
Solution 3 - C++Shadow2531View Answer on Stackoverflow
Solution 4 - C++ashwin911View Answer on Stackoverflow
Solution 5 - C++StormByteView Answer on Stackoverflow
Solution 6 - C++VernView Answer on Stackoverflow
Solution 7 - C++Oleg SvechkarenkoView Answer on Stackoverflow
Solution 8 - C++Ciro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 9 - C++TimesquareView Answer on Stackoverflow
Solution 10 - C++JemView Answer on Stackoverflow
Solution 11 - C++JustTiredView Answer on Stackoverflow
Solution 12 - C++DarrinView Answer on Stackoverflow
Solution 13 - C++DarrinView Answer on Stackoverflow
Solution 14 - C++Patricio RossiView Answer on Stackoverflow
Solution 15 - C++cigienView Answer on Stackoverflow