Iterators skipping characters

I want to reverse the cases of the letters in a text file.

The code below doesn't work for me.
Any ideas for fixing it, or for another approach?
Thanks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <cctype>
#include <fstream>
#include <iterator>

int main()
{
	std::fstream targetFile("file.txt");
	std::istreambuf_iterator<char> isbi(targetFile);
	std::ostreambuf_iterator<char> osbi(targetFile);

	for (; isbi != std::istreambuf_iterator<char>(); ++isbi, ++osbi)
		if (std::isupper(*isbi))
			*osbi = std::tolower(*isbi);
		else
		if (std::islower(*isbi))
			*osbi = std::toupper(*isbi);
}


original
Hello, World!


modified
heLlO, woRlD!

I did something like that once.
I checked to see if the char value was between the hex values for 'a' and 'z', then if it was I would subtract 0x20 as that would convert a lowercase letter to capital. The reverse was done for capital letters.
Probably because you are tring to read and write to the file
gustgulkan is right, and the underlying reason is that fstream has only one position, shared for both reading and writing (which is a limitation of the underlying C API). When you read a character, you advance the file pointer, and when you write a character, you advance it again.

Other streams (stringstream, for example) have two independent positions, and your approach works:

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

int main()
{
//  std::fstream targetFile("file.txt");
    std::stringstream targetFile("Hello, World");
    std::istreambuf_iterator<char> isbi(targetFile);
    std::ostreambuf_iterator<char> osbi(targetFile);

    for (; isbi != std::istreambuf_iterator<char>(); ++isbi, ++osbi)
        if (std::isupper(*isbi))
            *osbi = std::tolower(*isbi);
        else
        if (std::islower(*isbi))
            *osbi = std::toupper(*isbi);
        else
            *osbi = *isbi; // you forgot to perserve non-letters

    std::cout << targetFile.str() << '\n';
}


As for files, the simplest approach would be to read the file into a container (e.g. string), process, and then write it back.

Last edited on
Thank you for the replies.

gustgulkan is right, and the underlying reason is that fstream has only one position, shared for both reading and writing (which is a limitation of the underlying C API). When you read a character, you advance the file pointer, and when you write a character, you advance it again.

So I guess this is why std::iostream_iterator and std::iostreambuf_iterator don't exist.

Edit: hmm, then again such iterators would be a bit clumsy.
Last edited on
Topic archived. No new replies allowed.