You have a text file that contains tabs or spaces, and you want to convert from one to the other. For example, you may want to replace all tabs with three spaces, or you may want to do just the opposite and replace occurrences of some number of spaces with a single tab.
Regardless of whether you are replacing tabs with spaces or spaces with tabs, use the
ifstream
and ofstream
classes in <fstream>
. In
the first (simpler) case, read data in with an input stream, one character at a time,
examine it, and if it’s a tab, write some number of spaces to the output stream. Example 4-23 demonstrates how to do
this.
Example 4-23. Replacing tabs with spaces
#include <iostream> #include <fstream> #include <cstdlib> using namespace std; int main(int argc, char** argv) { if (argc < 3) return(EXIT_FAILURE); ifstream in(argv[1]); ofstream out(argv[2]); if (!in || !out) return(EXIT_FAILURE); char c; while (in.get(c)) { if (c == '\t') out << " "; // 3 spaces else out << c; } out.close(); if (out) return(EXIT_SUCCESS); else return(EXIT_FAILURE); }
If, instead, you need to replace spaces with tabs, see Example 4-24. It contains the function
spacesToTabs
that reads from an input stream, one
character at a time, looking for three consecutive spaces. When it finds three in a row,
it writes a tab to the output stream. For all other characters, or for fewer than three
spaces, whatever is read from the input stream is written to the output stream.
Example 4-24. Replacing spaces with tabs
#include <iostream> #include <istream> #include <ostream> #include <fstream> #include <cstdlib> using namespace std; void spacesToTabs(istream& in, ostream& out, int spaceLimit) { int consecSpaces = 0; char c; while (in.get(c)) { if (c != ' ') { if (consecSpaces > 0) { for (int i = 0; i < consecSpaces; i++) { out.put(' '); } consecSpaces = 0; } out.put(c); } else { if (++consecSpaces == spaceLimit) { out.put('\t'); consecSpaces = 0; } } } } int main(int argc, char** argv) { if (argc < 3) return(EXIT_FAILURE); ifstream in(argv[1]); ofstream out(argv[2]); if (!in || !out) return(EXIT_FAILURE); spacesToTabs(in, out, 3); out.close(); if (out) return(EXIT_SUCCESS); else return(EXIT_FAILURE); }
The mechanism for both of these solutions is the same; only the algorithms differ.
Read characters from an input stream using get
, and put
them to an output stream with put
. Put your logic for
doing the translation between calls to these two functions.
You probably noticed in Example 4-24
that in main
I declared in
and out
to be of types ifstream
and ofstream
,
respectively, and that the parameters to spacesToTabs
are actually istream
and ostream
. I did this to allow spacesToTabs
to work on any kind of input or output streams (well, not any kind of
stream—ones that inherit from basic_istream
or basic_ostream
), and not just file streams. For example, you
may have the text you want to reformat in a string stream (istringstream
and ostringstream
in
<sstream>
). In that case, do something like
this:
istringstream istr; ostringstream ostr; // fill up istr with text... spacesToTabs(istr, ostr);
As with strings, streams are actually class templates that are parameterized on the
type of character the stream operates on. For example, an ifstream
is a typedef
for basic_ifstream<char>
, and a wifstream
is a typedef
for basic_ifstream<wchar_t>
. Thus, if you need spacesToTabs
from Examples Example 4-23 or Example 4-24 to work on a stream of any kind
of character, you can use the class templates instead of the typedefs
:
template<typename T> void spacesToTabs(std::basic_istream<T>& in, std::basic_ostream<T>& out, int spaceLimit) { //...
Get C++ Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.