In your code here, I replaced s
with input_str
, and a
with vowels
, for readability:
for (int i = 0; i < input_str.length(); i++){
for(int j = 0; j < vowels.length(); j++){
if(input_str[i] == vowels[j]){
input_str.erase(input_str.begin() + i);
}
}
}
The problem with your current code above is that each time you erase a char in the input string, you should break out of the vowels j
loop and start over again in the input string at the same i
location, checking all vowels in the j
loop again. This is because erasing a char left-shifts all chars which are located to the right, meaning that the same i
location would now contain a new char to check since it just left-shifted into that position from one position to the right. Erroneously allowing i
to increment means you skip that new char to check in that same i
position, thereby leaving the 2nd vowel in the string if 2 vowels are in a row, for instance. Here is the fix to your immediate code from the question:
int i = 0;
while (i < s.length()){
bool char_is_a_vowel = false;
for(int j = 0; j < a.length(); j++){
if(s[i] == a[j]){
char_is_a_vowel = true;
break; // exit j loop
}
}
if (char_is_a_vowel){
s.erase(s.begin() + i);
continue; // Do NOT increment i below! Skip that.
}
i++;
}
However, there are many other, better ways to do this. I'll present some below. I personally find this most-upvoted code difficult to read, however. It requires extra study and looking up stuff to do something so simple. So, I'll show some alternative approaches to that answer.
Approach 1 of many: copy non-vowel chars to new string:
So, here is an alternative, simple, more-readable approach where you simply scan through all chars in the input string, check to see if the char is in the vowels string, and if it is not, you copy it to an output string since it is not a vowel:
Just the algorithm:
std::string output_str;
for (const char c : input_str) {
if (vowels.find(c) == std::string::npos) {
output_str.push_back(c);
}
}
Full, runnable example:
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
int main()
{
std::string input_str = "zjuotps";
std::string vowels = "aeiouyAEIOUY";
std::string output_str;
for (const char c : input_str)
{
if (vowels.find(c) == std::string::npos)
{
// char `c` is NOT in the `vowels` string, so append it to the
// output string
output_str.push_back(c);
}
}
std::cout << "input_str = " << input_str << std::endl;
std::cout << "output_str = " << output_str << std::endl;
}
Output:
input_str = zjuotps
output_str = zjtps
Approach 2 of many: remove vowel chars in input string:
Alternatively, you could remove the vowel chars in-place as you originally tried to do. But, you must NOT increment the index, i
, for the input string if the char is erased since erasing the vowel char left-shifs the remaining chars in the string, meaning that we need to check the same index location again the next iteration in order to read the next char. See the note in the comments below.
Just the algorithm:
size_t i = 0;
while (i < input_str.length()) {
char c = input_str[i];
if (vowels.find(c) != std::string::npos) {
input_str.erase(input_str.begin() + i);
continue;
}
i++;
}
Full, runnable example:
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
int main()
{
std::string input_str = "zjuotps";
std::string vowels = "aeiouyAEIOUY";
std::cout << "BEFORE: input_str = " << input_str << std::endl;
size_t i = 0;
while (i < input_str.length())
{
char c = input_str[i];
if (vowels.find(c) != std::string::npos)
{
// char `c` IS in the `vowels` string, so remove it from the
// `input_str`
input_str.erase(input_str.begin() + i);
// do NOT increment `i` here since erasing the vowel char above just
// left-shifted the remaining chars in the string, meaning that we
// need to check the *same* index location again the next
// iteration!
continue;
}
i++;
}
std::cout << "AFTER: input_str = " << input_str << std::endl;
}
Output:
BEFORE: input_str = zjuotps
AFTER: input_str = zjtps
Approach 3 of many: high-speed C-style arrays: modify input string in-place
I borrowed this approach from "Approach 1" of my previous answer here: Removing elements from array in C
If you are ever in a situation where you need high-speed, I'd bet this is probably one of the fastest approaches. It uses C-style strings (char arrays). It scans through the input string, detecting any vowels. If it sees a char that is NOT a vowel, it copies it into the far left of the input string, thereby modifying the string in-place, filtering out all vowels. When done, it null-terminates the input string in the new location. In case you need a C++ std::string
type in the end, I create one from the C-string when done.
Just the algorithm:
size_t i_write = 0;
for (size_t i_read = 0; i_read < ARRAY_LEN(input_str); i_read++) {
bool char_is_a_vowel = false;
for (size_t j = 0; j < ARRAY_LEN(input_str); j++) {
if (input_str[i_read] == vowels[j]) {
char_is_a_vowel = true;
break;
}
}
if (!char_is_a_vowel) {
input_str[i_write] = input_str[i_read];
i_write++;
}
}
input_str[i_write] = '\n';
Full, runnable example:
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
/// Get the number of elements in an array
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
int main()
{
char input_str[] = "zjuotps";
char vowels[] = "aeiouyAEIOUY";
std::cout << "BEFORE: input_str = " << input_str << std::endl;
// Iterate over all chars in the input string
size_t i_write = 0;
for (size_t i_read = 0; i_read < ARRAY_LEN(input_str); i_read++)
{
// Iterate over all chars in the vowels string. Only retain in the input
// string (copying chars into the left side of the input string) all
// chars which are NOT vowels!
bool char_is_a_vowel = false;
for (size_t j = 0; j < ARRAY_LEN(input_str); j++)
{
if (input_str[i_read] == vowels[j])
{
char_is_a_vowel = true;
break;
}
}
if (!char_is_a_vowel)
{
input_str[i_write] = input_str[i_read];
i_write++;
}
}
// null-terminate the input string at its new end location; the number of
// chars in it (its new length) is now equal to `i_write`!
input_str[i_write] = '\n';
std::cout << "AFTER: input_str = " << input_str << std::endl;
// Just in case you need it back in this form now:
std::string str(input_str);
std::cout << " C++ str = " << str << std::endl;
}
Output:
BEFORE: input_str = zjuotps
AFTER: input_str = zjtps
C++ str = zjtps
See also:
- [a similar answer of mine in C] Removing elements from array in C