1

I have written this simple program in C++ to print the contents of a .txt file.

void printrules(){
    string rule_path = "myfiles/rulebook.txt";
    ifstream fin;
    fin.open(rule_path.c_str());

    if (fin.fail()){
        cout << "Sorry, there was an error in displaying the rules." <<endl;
    }

    string x;
    while (fin >> x)
        cout << x << " ";

    fin.close();
}

int main(){
    printrules;
}

But I cannot think of a way to stop the words from getting "cut" when they are output to the console. For example:

image

In the first line, 'h' and 'e' got separated, and the same thing happened for the last words in the second and third lines too.

Is there a way to make sure the words remain whole without making the length of the lines fixed?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 2
    Does this answer your question? [Basic C++ Text Justification](https://stackoverflow.com/questions/42894749/basic-c-text-justification) – Kiran Mistry May 03 '20 at 06:12
  • @Kiran Mistry That post did help me understand justification but it is not what I'm looking for here. The OP in the post mentioned that they want to right-left justify their text within a character limit, but that's not the case for me; I just want the words to not be cut regardless of the console size – miniminimish May 03 '20 at 06:38
  • 1
    You are welcome to use my `PrettyPrint` routine I did for an open source project. You just invoke `PrettyPrint(string, N)` and it will left justify just about any reasonable input to fit within N columns. Try invoking it with `PrettyPrint(yourstring, 78)`. Sample pic [here](https://imgur.com/a/yq0i6GW). [Code on Github is here](https://github.com/jselbie/stunserver/blob/master/common/prettyprint.cpp) – selbie May 03 '20 at 06:59
  • `fin.open(rule_path.c_str());` why on earth do you do this when streams can open file paths as strings? Just use `fin.open(rule_path);` – phuclv Jul 23 '21 at 14:52

2 Answers2

1

There are quite a few ways to do this, but here's one that's fairly simple and easy.

#include <sstream>
#include <string>
#include <iostream>

void wrap(std::string const &input, size_t width, std::ostream &os, size_t indent = 0) {
    std::istringstream in(input);

    os << std::string(indent, ' ');
    size_t current = indent;
    std::string word;

    while (in >> word) {
        if (current + word.size() > width) {
            os << "\n" << std::string(indent, ' ');
            current = indent;
        }
        os << word << ' ';
        current += word.size() + 1;
    }
}

int main() {
    char *in = "There was a time when he would have embraced the change that was coming. In his youth he"
    " sought adventure and the unknown, but that had been years ago. He wished he could go back and learn"
    " to find the excitement that came with change but it was useless. That curiousity had long ago left"
    " him to where he had come to loathe anything that put him out of his comfort zone.";

    wrap(in, 72, std::cout, 0);
    return 0;
}

This implicitly assumes that you want to remove an extra white space that might be present in your input string, so if (for example) you started with your text formatted for 60 columns with a 5-character indent:

     There was a time when he would have embraced the change
     that was coming. In his youth he sought adventure and
     the unknown, but that had been years ago. He wished he
     could go back and learn to find the excitement that
     came with change but it was useless. That curiousity
     had long ago left him to where he had come to loathe
     anything that put him out of his comfort zone.

...but you asked for it to be word-wrapped at 72 columns with no indentation, it would get rid of the white space being used for the previous indentation, so it would come out like this:

There was a time when he would have embraced the change that was coming.
In his youth he sought adventure and the unknown, but that had been
years ago. He wished he could go back and learn to find the excitement
that came with change but it was useless. That curiousity had long ago
left him to where he had come to loathe anything that put him out of his
comfort zone.

Another possibility, especially if you want to word-wrap all the output to a particular stream, would be to use the word-wrapping streambuf I posted in another answer.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

I took the accepted answer above and made it so the modified it so the stringstream would be able to detect newlines from the original input text. Here's the code:

void wrap(std::string const &input, int width, std::ostream &os, size_t indent = 0) {std::istringstream in(input);
os << std::string(indent, ' ');
size_t current = indent;
std::string line;
std::string word;
string output = "";

while(getline(in,line))
{
    std::istringstream linein(line);
    while (linein >> word) {
        if (current + word.size() > width) {
            output += "\n" + std::string(indent, ' ');
            current = indent;
        }
        output +=  word + ' ';
        current += word.size() + 1;
    }
    output += "\n" + std::string(indent, ' ');
    current = indent;
}

os << output;

I'm new to using stackoverflow, so I hope the formatting doesn't come out too ugly.

Cheers!

chefjeff
  • 37
  • 6