Iterators skipping characters

Nov 12, 2012 at 6:50pm
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!

Nov 12, 2012 at 6:59pm
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.
Nov 12, 2012 at 7:43pm
Probably because you are tring to read and write to the file
Nov 12, 2012 at 8:17pm
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 Nov 12, 2012 at 8:24pm
Nov 12, 2012 at 9:04pm
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 Nov 12, 2012 at 9:08pm
Topic archived. No new replies allowed.