如何在 C++ 中对齐用户输入(不使用 iomanip)

How to align user input in C++ (not using iomanip)

提问人:Roy Pugh 提问时间:4/6/2019 最后编辑:Roy Pugh 更新时间:4/7/2019 访问量:1229

问:

我的程序应该根据用户指定的内容对齐输入的文本,到目前为止,我已经让它更改宽度但不对齐文本(左、右、中)。我已经看过了,但对我的情况没有帮助。到目前为止,我得到的代码是<iomanip>

#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;
}

但这只会调整宽度,所以我的输出是

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) 

这很好,但我还需要对齐左、右、居中,具体取决于用户输入的内容。我用过,但没用。如何使输出左对齐、右对齐或居中?<iomanip>

C++ IOstream iomanip

评论

0赞 David C. Rankin 4/6/2019
我唯一的想法是,既然你已经有了盒子的大小,例如,为什么不把它做成一个字符串。对于右对齐的文本,无需担心将输入拆分为单词。你知道开头和结尾的字符都被拿走了。因此,要填充右对齐,只需在输入字符串上使用反向迭代器来写入从 中倒数第二个位置开始的字符。"| |""| |"
0赞 eesiraed 4/6/2019
我假设你不使用是因为你不被允许,而不是因为你不知道怎么做?有了 .<iomanip><iomanip>

答:

1赞 Swordfish 4/6/2019 #1

简单快速。但你应该明白。

#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)]);
}

试运行:

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   |
+--------------------------------------+

修复了代码 - 不再吞下单词和最后一行。但我拒绝为示例输出重新运行它树时间。

评论

0赞 Swordfish 4/7/2019
@Roy我只是添加了一行数字来帮助我测试框的宽度是否正确。您使用哪种编译器?我怀疑还是?如果是这样,你可能会添加甚至添加到你的编译器选项中。IDE 并不重要。你得到的错误(哪个?)来自你的编译器。gccclang-std=c++11-std=c++14
0赞 Swordfish 4/7/2019
一些数字来帮助计数:for (int i = 1; i <= width; ++i) std::cout << ii % 10;
0赞 Roy Pugh 4/7/2019
据我所知,我得到的错误是由于语法:。诸如此类的东西。但我认为你是对的,这与我的编译器有关。/src/playground.cpp:19:34: error: expected ';' after top level declarator alignment_t const align_choices[]{ align_left, align_right, align_center };
0赞 Swordfish 4/7/2019
>我想让程序保持运行,直到用户输入 0 作为宽度,如果你谈论的是单次按键反应,而使用 Stndat-C++ 你不能。如果您想要建议,请获取有关C++的好教科书并重新开始。
0赞 Swordfish 4/7/2019
@RoyPugh显示的代码中绝对没有这种简单的语法错误。