3

My program is supposed to align inputted text based on what the user specifies, so far I've gotten it to change the width but not align the text (Left, Right, Center). I've seen <iomanip> but it doesn't help in my case. The code I've gotten so far is

#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
using namespace std;

string repeatChar(char c, int n) {
    string out;
    for (; n > 0; n--) {
        out.push_back(c);
    }
    return out;
}
vector<string> getInput() {
    vector<string> output;
    string line;
    cout << "Enter text, empty return will quit the input" << endl;
    do {
        cout << "> ";
        getline(cin, line);
        if (line.empty())
            continue;
        istringstream in(line);
        string word;
        while (in.good()) {
            in >> word;
            if (!word.empty())
                output.push_back(word);
        }

    } while (!line.empty());
    return output;
}
void printLine(vector<string>::iterator start, vector<string>::iterator end,
        int width) {
    if(start == end)
        return;
    int chars = 0;
    int spaces = -1;
    vector<string> currentLine;
    for (; start != end; start++) {
        string &word = *start;
        int newchars = chars + word.length();
        int newspaces = spaces + 1;
        if (newchars + newspaces <= width) {
            currentLine.push_back(word);
            chars = newchars;
            spaces = newspaces;
        } else
            break;
    }
    cout << '|';
    if (spaces <= 0) {
        cout << currentLine[0] << repeatChar(' ', (width - chars));
    } else {
        int spaceWidth = (width - chars) / spaces;
        int extraWidth = (width - chars) % spaces;
        int i;
        for (i = 0; i < currentLine.size() - 1; i++) {
            cout << currentLine[i];
            cout << repeatChar(' ', spaceWidth);
            if (extraWidth > 0) {
                cout << ' ';
                extraWidth--;
            }
        }
        cout << currentLine[i];
    }
    cout << '|' << endl;
    printLine(start, end, width);
    return;
}
void printJustify(vector<string> words, int width) {
cout << '+' << repeatChar('-', width) << '+' << endl;
printLine(words.begin(), words.end(), width);
cout << '+' << repeatChar('-', width) << '+' << endl;
}
int main() {
vector<string> input = getInput();
int maxWidth = 0;
for (int i = 0; i < input.size(); i++) {
    maxWidth = (input[i].length() > maxWidth) ? input[i].length() : maxWidth;
}
int width;
do {
    cout << "> Enter width of text and align(Left, Right, Center) ";
    cin >> width;
    if (width == 0)
        continue;
    width = (width < maxWidth) ? maxWidth : width;
    printJustify(input, width);
} while (width > 0);
return 0;
}

but this only adjusts the width so my output is

Enter text, empty return will quit the input
> There are many types of Parrots in the world,
> for example, African Greys, Macaws, 
> Amazons. And much much more. 
> 
> Enter width of text and align(Left, Right, Center) 30
+------------------------------+
|There   are   many   types  of|
|Parrots   in  the  world,  for|
|example,     African    Greys,|
|Macaws,  Macaws,  Amazons. And|
|much    much    more.    more.|
+------------------------------+
> Enter width of text and align(Left, Right, Center) 

This is great but I also need to align Left, Right, Center, depending on what the user inputs. I've used <iomanip> but that hasn't been useful. How can I get the output to align left, right, or center?

Roy Pugh
  • 31
  • 3
  • My only thoughts would be since you already have the size of your box, e.g. `"| |"`, why not make that a string. For right-justified text, don't worry about splitting the input into words. You know the beginning and end characters are taken. So for filling right-justified, just use a reverse iterator on your input string to write those characters beginning with the next to last position in `"| |"`. – David C. Rankin Apr 05 '19 at 23:23
  • I assume you're not using `` because you're not allowed to, not because you don't know how? Things are a lot easier with ``. – eesiraed Apr 06 '19 at 03:42

1 Answers1

1

Quick and dirty. But you should get the idea.

#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <algorithm>

std::string get_text(std::istream &is = std::cin)
{
    std::string text;

    for(std::string line; std::cout << "> ", std::getline(is, line) && !line.empty(); text += ' ' + line);

    return text;
}

enum alignment_t { align_left, align_right, align_center };
alignment_t const align_choices[]{ align_left, align_right, align_center };
char const *align_choices_strings[]{ "Left", "Right", "Center" };

std::string extract_line(std::stringstream &ss, int max_width)
{
    std::string line;
    std::string word;
    while ((ss >> word) && line.length() + word.length() + 1 <= max_width)
        line += word + ' ';

    if(line.length())
        line.pop_back();

    if (line.length() + word.length() + 1 >= max_width) {
        std::stringstream temp;
        temp << word;
        temp << ss.rdbuf();
        ss.swap(temp);
    }

    return line;
}

void print_box(std::string const &text, int width, alignment_t alignment = align_left, std::ostream &os = std::cout)
{
    for (int i = 1; i <= width; ++i)
        os << i % 10;
    os << '\n';

    os << '+' << std::setw(width) << std::setfill('-') << "+\n";

    std::stringstream ss;
    ss.str(text);

    for (std::string line{ extract_line(ss, width - 2) }; line.length(); line = extract_line(ss, width - 2)) {

        os << std::setw(1) << '|' << std::setw(width - 2) << std::setfill(' ');

        switch (alignment) {
        case align_left:
            os << std::left << line << std::setw(1) << "|\n";;
            break;

        case align_right:
            os << std::right << line << std::setw(1) << "|\n";;
            break;

        case align_center:
        {
            int fill = (width - line.length()) / 2;
            os << std::setw(fill + line.length()) << std::right << line << std::setw(width - line.length() - fill) << "|\n";
            break;
        }
        }
    }

    os << std::setw(1) << '+' << std::setw(width) << std::setfill('-') << std::right << "+\n";
}

int main()
{
    std::cout << "Enter text, empty return will quit the input\n";
    auto text{ get_text() };

    std::cout << "> Enter width of text and align(Left, Right, Center): ";
    int width;
    std::string alignment;
    auto alignment_choice{ std::cbegin(align_choices_strings) };

    if (!(std::cin >> width >> alignment) ||
        (alignment_choice = std::find(std::cbegin(align_choices_strings), std::cend(align_choices_strings), alignment))
        == std::cend(align_choices_strings))
    {
        std::cerr << "Input error.\n\n";
        std::cout << "Bye.\n\n";
        return EXIT_FAILURE;
    }

    print_box(text, width, align_choices[alignment_choice - std::cbegin(align_choices_strings)]);
}

Sample Runs:

Enter text, empty return will quit the input
> The journey began at
> Folly Bridge near Oxford
> and ended five miles away
> in the village of
> Godstow. During the trip
> Charles Dodgson told the
> girls a story that
> featured a bored little
> girl named Alice who goes
> looking for an adventure.
>
> Enter width of text and align(Left, Right, Center): 25 Right
+-----------------------+
|   The journey began at|
| Bridge near Oxford and|
| five miles away in the|
| of Godstow. During the|
|   Charles Dodgson told|
|     girls a story that|
|    a bored little girl|
| Alice who goes looking|
+-----------------------+
Enter text, empty return will quit the input
> The journey began at
> Folly Bridge near Oxford
> and ended five miles away
> in the village of
> Godstow. During the trip
> Charles Dodgson told the
> girls a story that
> featured a bored little
> girl named Alice who goes
> looking for an adventure.
>
> Enter width of text and align(Left, Right, Center): 30 Center
+----------------------------+
|  The journey began at Folly|
|  near Oxford and ended five|
|    away in the village of  |
|   During the trip Charles  |
| told the girls a story that|
|  a bored little girl named |
+----------------------------+
Enter text, empty return will quit the input
> The journey began at
> Folly Bridge near Oxford
> and ended five miles away
> in the village of
> Godstow. During the trip
> Charles Dodgson told the
> girls a story that
> featured a bored little
> girl named Alice who goes
> looking for an adventure.
>
> Enter width of text and align(Left, Right, Center): 40 Left
+--------------------------------------+
|The journey began at Folly Bridge     |
|Oxford and ended five miles away in   |
|village of Godstow. During the trip   |
|Dodgson told the girls a story that   |
|a bored little girl named Alice who   |
+--------------------------------------+

// fixed the code - doesn't swallow words and the last line any longer. But I refuse to rerun it tree times for the sample output.

Swordfish
  • 12,971
  • 3
  • 21
  • 43
  • @Roy i just added a line of numbers to help me testing if the width of the box was correct. Which compiler do you use? I suspect `gcc` or `clang`? If so you might neet do add `-std=c++11`or even `-std=c++14` to your compiler options. The IDE doesn't matter that much. The errors you get (which?) come from your compiler. – Swordfish Apr 06 '19 at 16:45
  • A number of digits to help counting: `for (int i = 1; i <= width; ++i) std::cout << ii % 10;` – Swordfish Apr 06 '19 at 16:47
  • the errors I get as far as I can tell is due to syntax: `/src/playground.cpp:19:34: error: expected ';' after top level declarator alignment_t const align_choices[]{ align_left, align_right, align_center };`. Stuff like that. But I think you are correct, it has to do with my compiler. – Roy Pugh Apr 06 '19 at 18:45
  • > I wanted to keep the program running until the user inputs 0 as the width if you're talking about reacting on a single keypress, with Stndat-C++ you can't. If you want an advise, please, get a good textbook about C++ and start over. – Swordfish Apr 06 '19 at 20:44
  • @RoyPugh there are definitely no such simple syntax errors in the code shown. – Swordfish Apr 07 '19 at 06:39