Using string::erase

Hello, I've been reading the string reference and playing around with everything I can manage to figure out. I'm trying to use erase to remove vowels from a string but I can't get it to do so.

Here's my code, I know it's terrible

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <string>

using namespace std;

void remVowel(string &s);

int main()
{
	string s1;
	char vowels[] = {'a', 'e', 'i', 'o', 'u'};

	cout<<"Enter a string: ";
	getline(cin,s1);

	for(int i = 0; i < 5; i++)
	{
		s1.erase(vowels[i]);
	}

	cout<<endl;
	cout<<s1<<endl;
}
Last edited on
string::erase takes two int parameters representing the starting index and the number of characters to erase, the latter having a default value of 'npos', which means 'the rest of the string'.

What you're doing (first time round your for loop) is erasing all the characters from index 'a' onwards, 'a' being the character 'a', with ASCII value 197. If you entered a string longer than 197 characters, you'd see it being truncated to 197.

What you need to do is search for each vowel's position in the string and pass that position to erase. See the string::find() function for clues.

Jim
Hi Jim, I tried using the find() function to search for it like this:

1
2
3
4
5
for(int i = 0; i < 5; i++)
{
	int f1 = s1.find("a");
	s1.erase(f1,s1.length());
}


Any string I enter with or without the find function gives me an std::out_of_range error, I tried removing the loop and simplifying things as much as I could think of but I get the same error no matter what string I input.

Where am I going wrong?
Sorry for the delay - had to go home and have some dinner ;-)

You're almost right - the second parameter to string::erase() is the number of characters to erase. You don't want to be removing s1.length() characters - that's the whole string, and starting erasing from the first 'a' is running off the end and causing your error. Just erase the one character for the 'a' you've just found.

Also, your loop as it is needs a bit of rework to find vowels[i], not 'a', and you'll need an inner loop to repeat the find/erase combination until all examples of that character are gone, not just the first one.

[Edit]
Oh, and make sure you check the returned f1 value from find - if it returns npos, the character wasn't found, so don't erase that character - you can end your inner loop there.

Cheers,
Jim
Last edited on
Thanks for the reply, the "a" I put there was just to simplify things for myself so I could find the problem through elimination.

I'm a lot closer now since I'm getting an output with characters erased but they're not necessarily the vowels since I'm setting it to s1.erase(1,1);

I can see the problem is with my f1 variable, for some reason it's causing the out of range error.

Here's the code:

1
2
3
4
5
6
7
8
9
for(int i = 0; i < s1.length(); i++)
	{
		int f1 = s1.find(vowels[i]); // This only works if I do s1.find("a");
		for(int j = 0; j <= i; j++)
		{
			s1.erase(f1,1); // f1 only works if I set the above to a fixed letter
			cout<<s1<<endl; // This is in the loop to see what it's doing
		}	
	}


Last edited on
Ah, I see the problem now - your original loop (with 'i') was running from 0 to 4 (through the vowels array) - you're now running from 0 to the length of s1 but are using it to index the vowels array. vowels is 5 chars long, but if s1 is any longer than that you're going to get bounds errors (which won't necessarily show up immediately/obviously).

Pseudo(ish)-code for what you have to do is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (int i = 0; i < 5; ++i) // use i to index the vowels
{
  // Now repeatedly check whether s1 has any vowels[i] characters using find()
  int f1 = s1.find(vowels[i]);
  while (f1 != string::npos) // If it's not npos, f1 now holds the position of the vowel
  {
    s1.erase(f1, 1); // Erase that one vowel character
    f1 = s1.find(vowels[i]); // See if there are any more
  }

  // Inner while loop has finished because f1 == npos
  // We can now run round the outer loop again, with i incremented by 1
  // finding all instances of the next vowel in the vowels array.
}


[Edit] - OK, so it's not pseudo code at all

Cheers,
Jim
Last edited on
If an algorithm/bit of code isn't working as expected, I often find it useful to run through an example on paper, following your code and adjusting the data at each step. It soon becomes obvious where the problem is. Try it with your code from your last post and see what's actually going on.

Jim
Since a string is much like a vector, you can iterate using iterators over the string, and erase can take in an iterator to erase and returns a valid iterator.

So you can do something like this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main()
	{
	string helloWorld = "Hello World!";

	string::iterator iter = helloWorld.begin();

	while ( iter != helloWorld.end() )
		{
		if ( (*iter) == 'a' || (*iter) == 'e' || (*iter) == 'i' || (*iter) == 'o' || (*iter) == 'u' )
			{
			iter = helloWorld.erase( iter );
			}
		else
			{
			++iter;
			}
		}

	cout << helloWorld << '\n';
	cin.get();
	return 0;
	}


If you don't like iterators you can do

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

int main()
	{
	string helloWorld = "Hello World!";

	for ( int i = 0; i < helloWorld.length(); )
		{
		if ( helloWorld[i] == 'a' || helloWorld[i] == 'e' || helloWorld[i] == 'i' || helloWorld[i] == 'o' || helloWorld[i] == 'u' )
			{
			helloWorld.erase( i, 1 );
			}
		else
			{
			++i;
			}
		}

	cout << helloWorld << '\n';
	cin.get();
	return 0;
	}


There is room for optimizations here, but I wrote it so it is very clear.
Last edited on
Since a string is a container (much like a vector), you could also erase-remove:

s1.erase(remove_if(s1.begin(), s1.end(), isvowel), s1.end());
where isvowel() would be a user-provided function/functor that takes a char and returns a bool. Demo: http://ideone.com/RQkSRt

But understanding string's index-oriented member functions is important too.
Last edited on
Thanks a lot guys, yeah Jim I usually write all my code on paper to help internalize it better but this was getting confusing for my level of knowledge, which most certainly has expanded with the 5 hours I invested playing around with this lol.

Thanks again!
Topic archived. No new replies allowed.