tags:

views:

233

answers:

3

I'm trying to edit a text file to remove the vowels from it and for some reason nothing happens to the text file. I think it may be because a mode argument needs to be passed in the filestream.

[SOLVED]

Code:

#include "std_lib_facilities.h"

bool isvowel(char s)
{
     return (s == 'a' || s == 'e' || s =='i' || s == 'o' || s == 'u';)
}


void vowel_removal(string& s)
{
     for(int i = 0; i < s.length(); ++i)
             if(isvowel(s[i]))
                      s[i] = ' ';
}

int main()
{
    vector<string>wordhold;
    cout << "Enter file name.\n";
    string filename;
    cin >> filename;
    ifstream f(filename.c_str());

    string word;
    while(f>>word) wordhold.push_back(word);

    f.close();

    ofstream out(filename.c_str(), ios::out);
    for(int i = 0; i < wordhold.size(); ++i){
            vowel_removal(wordhold[i]);
            out << wordhold[i] << " ";}


    keep_window_open();
}
A: 

Are you sure your while loop is actually executing? Try adding some debugging output to verify that it's doing what you think it is.

Matthew Iselin
I'm pretty sure it works considering that I have code very similar to this that works perfectly. I think the problem is in the declaration of the stream itself.
trikker
Pretty sure isn't the same as certain ;). Add some debug output, verify that the stream is valid, and know for certain.
Matthew Iselin
The stream is valid. I'll edit the debug code in.
trikker
The loop is executing, I checked
Gab Royer
+2  A: 

Files are sort of like a list, a sequential byte stream. When you open the file you position the file pointer at the very start, every read/write repositions the file pointer in the file with an offset larger than the last. You can use seekg() to move back in the file and overwrite previous content. Another problem with your approach above is that there will probably be some delimiters between the words typically one or more spaces for instance, you will need to handle read/write on these too.

It is much easier to just load the whole file in memory and do your manipulation on that string then rewriting the whole thing back.

Anders K.
I thought that since the string is a non const reference in the vowel_removal function that it would change the string accordingly and write it back. However, when I wrote the program I knew that it could have some issues since I wasn't sure what it was going to do with the actual file since no modes were passed in the argument. How would you suggest performing the approach you mentioned above? (Not the seekg(), loading the file and manipulating each string)
trikker
one way would be to load the file as a list of characters using a container from stl e.g. std::list<char> then just walk through the list eliminating all vowels ignoring any other chars.
Anders K.
+4  A: 

Reading and writing on the same stream results in an error. Check f.bad() and f.eof() after the loop terminates. I'm afraid that you have two choices:

  1. Read and write to different files
  2. Read the entire file into memory, close it, and overwrite the original

As Anders stated, you probably don't want to use operator<< for this since it will break everything up by whitespace. You probably want std::getline() to slurp in the lines. Pull them into a std::vector<std::string>, close the file, edit the vector, and overwrite the file.

Edit:

Anders was right on the money with his description. Think of a file as a byte stream. If you want to transform the file in place, try something like the following:

void
remove_vowel(char& ch) {
    if (ch=='a' || ch=='e' || ch=='i' || ch =='o'  || ch=='u') {
        ch = ' ';
    }
}

int
main() {
    char const delim = '\n';
    std::fstream::streampos start_of_line;
    std::string buf;
    std::fstream fs("file.txt");

    start_of_line = fs.tellg();
    while (std::getline(fs, buf, delim)) {
        std::for_each(buf.begin(), buf.end(), &remove_vowel);
        fs.seekg(start_of_line);     // go back to the start and...
        fs << buf << delim;          // overwrite the line, then ...
        start_of_line = fs.tellg();  // grab the next line start
    }
    return 0;
 }

There are some small problems with this code like it won't work for MS-DOS style text files but you can probably figure out how to account for that if you have to.

D.Shawley
I thought fstream was meant for reading and writing on the same stream? Would you recommend keeping the fstream, using the approach you described, and I'm guessing I should use the ios::out mode?
trikker
You can read and write the stream provided that you use `tellg()` and `setg()` to manage the file position yourself. I'll update my answer to provide an example.
D.Shawley
I kind of took what you said and did it in a (what I thought was) a simpler way than what you posted. It worked though so thank you! I'll post the code.
trikker