C ++ выравнивание при печати cout << - PullRequest
57 голосов
/ 21 марта 2010

Есть ли способ выровнять текст при печати с использованием std::cout? Я использую вкладки, но когда слова слишком большие, они больше не будут выравниваться.

Sales Report for September 15, 2010
Artist  Title   Price   Genre   Disc    Sale    Tax Cash
Merle   Blue    12.99   Country 4%  12.47   1.01    13.48
Richard Music   8.49    Classical   8%  7.81    0.66    8.47
Paula   Shut    8.49    Classical   8%  7.81    0.72    8.49

Ответы [ 6 ]

120 голосов
/ 21 марта 2010

Стандартный способ ISO C ++ - #include <iomanip> и использование таких манипуляторов, как std::setw.Тем не менее, эти манипуляторы ввода-вывода реальная боль использовать даже для текста, и их практически невозможно использовать для форматирования чисел (я предполагаю, что вы хотите, чтобы суммы в долларах выстраивались в десятичные числа, имели правильное количество значащих цифр и т. Д.).).Даже для простых текстовых меток код будет выглядеть примерно так для первой части вашей первой строки:

// using standard iomanip facilities
cout << setw(20) << "Artist"
     << setw(20) << "Title"
     << setw(8) << "Price";
// ... not going to try to write the numeric formatting...

Если вы можете использовать библиотеки Boost , запустите (не ходите) и используйте взамен библиотеку Boost.Format .Он полностью совместим со стандартными iostreams и дает вам все возможности для удобного форматирования с помощью строки форматирования printf / Posix, но при этом не теряя ни силы, ни удобства самих iostreams.Например, первые части первых двух строк будут выглядеть примерно так:

// using Boost.Format
cout << format("%-20s %-20s %-8s\n")  % "Artist" % "Title" % "Price";
cout << format("%-20s %-20s %8.2f\n") % "Merle" % "Blue" % 12.99;
11 голосов
/ 21 марта 2010

См. Также: Какую библиотеку ввода-вывода C следует использовать в коде C ++?

struct Item
{
   std::string     artist;
   std::string     c;
   integer         price;  // in cents (as floating point is not acurate)
   std::string     Genre;
   integer         disc;
   integer         sale;
   integer         tax;
};

std::cout << "Sales Report for September 15, 2010\n"
          << "Artist  Title   Price   Genre   Disc    Sale    Tax Cash\n";
FOREACH(Item loop,data)
{
    fprintf(stdout,"%8s%8s%8.2f%7s%1s%8.2f%8.2f\n",
          , loop.artist
          , loop.title
          , loop.price / 100.0
          , loop.Genre
          , loop.disc , "%"
          , loop.sale / 100.0
          , loop.tax / 100.0);

   // or

    std::cout << std::setw(8) << loop.artist
              << std::setw(8) << loop.title
              << std::setw(8) << fixed << setprecision(2) << loop.price / 100.0
              << std::setw(8) << loop.Genre
              << std::setw(7) << loop.disc << std::setw(1) << "%"
              << std::setw(8) << fixed << setprecision(2) << loop.sale / 100.0
              << std::setw(8) << fixed << setprecision(2) << loop.tax / 100.0
              << "\n";

    // or

    std::cout << boost::format("%8s%8s%8.2f%7s%1s%8.2f%8.2f\n")
              % loop.artist
              % loop.title
              % loop.price / 100.0
              % loop.Genre
              % loop.disc % "%"
              % loop.sale / 100.0
              % loop.tax / 100.0;
}
9 голосов
/ 21 марта 2010

Манипуляторы ввода-вывода - это то, что вам нужно. В частности, setw . Вот пример со справочной страницы:

// setw example
#include <iostream>
#include <iomanip>
using namespace std;

int main () {
  cout << setw (10);
  cout << 77 << endl;
  return 0;
}

Обоснование поля слева и справа выполняется с помощью манипуляторов left и right. Также взгляните на setfill . Вот более полное руководство по форматированию вывода C ++ с помощью манипуляторов io .

8 голосов
/ 21 марта 2010

Здесь вам поможет функция манипулятора setw .

7 голосов
/ 12 марта 2014

Другой способ выровнять столбец:

using namespace std;

cout.width(20); cout << left << "Artist";
cout.width(20); cout << left << "Title";
cout.width(10); cout << left << "Price";
...
cout.width(20); cout << left << artist;
cout.width(20); cout << left << title;
cout.width(10); cout << left << price;

Мы должны оценить максимальную длину значений для каждого столбца. В этом случае значения столбца «Исполнитель» не должны превышать 20 символов и т. Д.

4 голосов
/ 21 марта 2010

В то время, когда вы излучаете самую первую строку,

Artist  Title   Price   Genre   Disc    Sale    Tax Cash

Чтобы достичь «выравнивания», вы должны «заранее» знать, насколько широким должен быть каждый столбец (в противном случае выравнивание невозможно). Как только вы do узнаете необходимую ширину для каждого столбца (есть несколько возможных способов добиться этого в зависимости от того, откуда поступают ваши данные), тогда поможет функция setw, упомянутая в другом ответе, или ( более грубо ;-) вы могли бы выбросить тщательно вычисленное количество лишних пробелов (неуклюже, чтобы быть уверенным) и т. д. Я не рекомендую вкладки в любом случае, так как вы не имеете никакого реального контроля над тем, как конечное устройство вывода будет отображать их вообще.

Возвращаясь к основной проблеме, если у вас есть значение каждого столбца в vector<T>, например, вы можете выполнить первый этап форматирования, чтобы определить максимальную ширину столбца, например (обязательно с учетом ширины заголовка для столбца тоже конечно).

Если ваши строки поступают «одна за другой», и выравнивание имеет решающее значение, вам придется кэшировать или буферизовать строки по мере их поступления (в память, если они уместятся, в противном случае в файл на диске, который вы позже) «перемотать» и перечитать с самого начала), стараясь обновлять вектор «максимальной ширины каждого столбца» по мере появления строк. Вы не можете ничего выводить (даже заголовки!), Если важно сохранить выравнивание, пока вы не увидите самую последнюю строку (если, конечно, каким-то волшебным образом не обладаете предыдущим знанием ширины столбцов; -).

...