Настройка столбцов C++ с помощью cout

Итак, я только начинаю изучать С++, и мне любопытно, есть ли способ отформатировать ваш вывод с помощью cout, чтобы он выглядел красиво и структурирован в столбцах.

Например.

string fname = "testname";
    string lname = "123";
    double height = 1.6;

    string fname2 = "short";
    string lname2 = "123";
    double height2 = 1.8;

    cout << "Name" << setw(30) << "Height[m]" << endl;
    cout << fname + " " + lname << right << setw(20) << setprecision(2) << fixed << height << endl;
    cout << fname2 + " " + lname2 << right << setw(20) << setprecision(2) << fixed << height2 << endl

Вывод выглядит следующим образом:

 Name                   Height[m]
 testname 123              1.60
 short 123              1.80

Я хочу, чтобы это выглядело так:

Name                   Height[m]
testname 123             1.60
short 123                1.80

Проблема, которую я пытаюсь решить, заключается в том, что я хочу разместить высоту в определенной позиции от имени, но в зависимости от того, какую длину имени я беру, значение высоты либо уходит далеко вправо, либо будет очень близко к слева. Есть ли способ исправить это?


person user3611818    schedule 13.11.2015    source источник


Ответы (1)


Во-первых, с таким потоком вывода, как std::cout, вы не можете вернуться назад во времени и изменить вывод, который уже был выполнен. Это имеет смысл — просто представьте, что std::cout записал в файл, потому что вы запустили свою программу с помощью program.exe > test.txt, а test.txt был на USB-накопителе, который тем временем был отключен...

Так что вам нужно сразу все исправить.

В принципе, есть два способа сделать это.

Вы можете предполагать, что ни одна запись в первом столбце никогда не будет шире, чем определенное количество символов, что вы и пытались сделать. Проблема в том, что ваш setw находится в неправильном положении, а right должно быть left. Манипулятор потока должен быть размещен перед элементами, на которые следует воздействовать. И поскольку вам нужны столбцы с выравниванием по левому краю, вам нужно left:

cout << left << setw(20) << "Name" << "Height[m]" << endl;
cout << left << setw(20) << fname + " " + lname << setprecision(2) << fixed << height << endl;
cout << left << setw(20) << fname2 + " " + lname2 << setprecision(2) << fixed << height2 << endl;

Но это решение не очень общее. Что, если у вас будет имя с 21 символом? Или с 30 символами? Или 100 символов? Что вам действительно нужно, так это решение, в котором столбец автоматически устанавливается настолько широким, насколько это необходимо.

Единственный способ сделать это — собрать все записи перед их печатью, найти самую длинную, соответствующим образом установить ширину столбца и только затем распечатать все.

Вот одна из возможных реализаций этой идеи:

std::vector<std::string> const first_column_entries
{
    "Name",
    fname + " " + lname,
    fname2 + " " + lname2
};

auto const width_of_longest_entry = std::max_element(std::begin(first_column_entries), std::end(first_column_entries),
    [](std::string const& lhs, std::string const& rhs)
    {
        return lhs.size() < rhs.size();
    }
)->size();

// some margin:
auto const column_width = width_of_longest_entry + 3;

std::cout << std::left << std::setw(column_width) << "Name" << "Height[m]" << "\n";
std::cout << std::left << std::setw(column_width) << fname + " " + lname << std::setprecision(2) << std::fixed << height << "\n";
std::cout << std::left << std::setw(column_width) << fname2 + " " + lname2 << std::setprecision(2) << std::fixed << height2 << "\n";

Следующим шагом эволюции будет обобщение std::vector в самописный класс с именем Table и повторение строк этого Table в цикле для вывода записей.

person Christian Hackl    schedule 13.11.2015
comment
Вы должны добавить "Name" к first_column_entries. fname + " " + lname и fname2 + " " + lname2 могут привести к одному пробелу... - person Simon Kraemer; 13.11.2015
comment
@SimonKraemer: Хороший вопрос. Я воздержался от публикации полной программы, но это изменение имеет смысл. - person Christian Hackl; 13.11.2015