HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Remove all vowel from file C++

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fileallremovevowelfrom

Problem

i am just start to learn C++ and would like to know if there is a better and efficient way to solve this problem or some recommendations.


Problem: Remove all vowels from file and create new one without
vowels.

Here is my solution.

#include 
#include 

bool is_vowel(char &ch) {
    ch = tolower(ch);//clion showing warning here(value of type 'int' may not fit into type 'char') ,dont know why , i havent int here.
    return (ch == 'a' || ch == 'o' || ch == 'u' || ch == 'i' || ch == 'e');
}

int main() {
    ifstream file{"data.txt"};
    ofstream outfile{"new.txt"};
    string word;
    getline(file, word);
    for (char &ch : word) {
        if (!is_vowel(ch))
            outfile << ch;
    }
}

Solution

For the moment, let's ignore is_vowel itself, and just look at the higher level: what we're doing is copying data from some source to some destination, while removing any items that meet some specified criteria.

As it happens, the standard library already has an algorithm to do exactly that: std::remove_copy_if (I know: crappy name; not clear what it really does--but that really is what it does).

So, I will posit that at the top level, this is how we should be carrying out the overall task:

remove_copy_if(some_input, some_output, your_criteria);


In the case of files, we can use istream_iterators for the input and an ostream_iterator for the output, making this something like:

std::ifstream file{"data.txt"};
std::ofstream outfile{"new.txt"};

file >> std::noskipws;

std::istream_iterator in{file}, end;
std::ostream_iterator out{outfile};

std::remove_copy_if(in, end, out, is_vowel);


Looking at is_vowel itself: it can be defined a number of different ways, depending on the degree to which you care about speed vs. space usage. If you care primarily about space, storing the vowels in a string and searching that string (e.g., as suggested by @utnapistim) is a perfectly fine method. Under the circumstances (copying from one file to another) the I/O will almost certainly be (quite a lot) slower than the processing, so this is probably the most sensible approach.

For another possibility, however, let's assume our source and destination were just strings in memory instead, so we wanted to optimize for speed instead. In this case, we might consider a somewhat different approach. One possibility would be an array (or vector) of Booleans, one for each possible char value, specifying whether that character is a vowel. We probably want to wrap this up in a neat little class so we don't need to deal with the details.

class is_vowel {
    bool table[std::numeric_limits::max()];
    static const char vowels = "aeiouAEIOU";
public:
    // Here we set up our table. We start by initializing everything to `false`
    // then we set the entries that really do represent vowels to true.
    is_vowel() : table(false) {
        for (auto ch : vowels)
            table[ch] = true;
    }

    bool operator()(unsigned char ch) { return table[ch]; }
};


Unfortunately, it's not always easy to decide which sort of approach will be the best for a given circumstance, but such is life sometimes.

There are also a few intermediate points that probably don't make sense for this specific case, but can for similar cases. For example, here we're dealing with such a small number of items (around 10) that searching the string isn't particularly slow. If we had a list of, say, a few hundred items we wanted to remove, searching the whole list every time could get pretty slow--for such cases, we might consider sorting the list of items to remove, and using a binary search.

I'm starting to get into pretty hypothetical areas though, so perhaps I should just stop for now... :-)

Code Snippets

remove_copy_if(some_input, some_output, your_criteria);
std::ifstream file{"data.txt"};
std::ofstream outfile{"new.txt"};

file >> std::noskipws;

std::istream_iterator<char> in{file}, end;
std::ostream_iterator<char> out{outfile};

std::remove_copy_if(in, end, out, is_vowel);
class is_vowel {
    bool table[std::numeric_limits<unsigned char>::max()];
    static const char vowels = "aeiouAEIOU";
public:
    // Here we set up our table. We start by initializing everything to `false`
    // then we set the entries that really do represent vowels to true.
    is_vowel() : table(false) {
        for (auto ch : vowels)
            table[ch] = true;
    }

    bool operator()(unsigned char ch) { return table[ch]; }
};

Context

StackExchange Code Review Q#124928, answer score: 3

Revisions (0)

No revisions yet.