4.16. Wrapping Lines in a Text File

Problem

You want to “wrap” text at a specific number of characters in a file. For example, if you want to wrap text at 72 characters, you would insert a new-line character after every 72 characters in the file. If the file contains human-readable text, you probably want to avoid splitting words.

Solution

Write a function that uses input and output streams to read in characters with istream::get(char), do some bookkeeping, and write out characters with ostream::put(char). Example 4-25 shows how to do this for text files that contain human-readable text without splitting words.

Example 4-25. Wrapping text

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cctype>
#include <functional>

using namespace std;

void textWrap(istream& in, ostream& out, size_t width) {

   string tmp;
   char cur = '\0';
   char last = '\0';
   size_t i = 0;

   while (in.get(cur)) {
      if (++i == width) {
         ltrimws(tmp);                  // ltrim as in Recipe
         out << '\n' << tmp;            // 4.1
         i = tmp.length();
         tmp.clear();
      } else if (isspace(cur) &&   // This is the end of
                 !isspace(last)) { // a word
         out << tmp;
         tmp.clear();
      }
      tmp += cur;
      last = cur;
   }
}

int main(int argc, char** argv) {
   if (argc < 3)
      return(EXIT_FAILURE);

   int w = 72;
   ifstream in(argv[1]);
   ofstream out(argv[2]);

   if (!in || !out)
     return(EXIT_FAILURE);

   if (argc == 4)
     w = atoi(argv[3]);

   textWrap(in, out, w);

   out.close();

   if (out)
      return(EXIT_SUCCESS);
   else
      return(EXIT_FAILURE);
}

Discussion

textWrap reads characters, one at a time, from the input stream. Each character is appended to a temporary string, tmp, until it reaches the end of a word or the maximum line width. If it reaches the end of a word but is not yet at the maximum line width, the temporary string is written to the output stream. Otherwise, if the maximum line width has been exceeded, a new line is written to the output stream, the whitespace at the beginning of the temporary string is removed, and the string is written to the output stream. In this way, textWrap writes as much as it can to the output stream without exceeding the maximum line width. Instead of splitting a word, it bumps the word to the next line.

Example 4-25 uses streams nearly identically to Recipe 4.15. See that recipe for more information on what streams are and how to use them.

See Also

Recipe 4.15

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.