C++ alignment when printing cout <<

穿精又带淫゛_ 提交于 2019-11-26 12:07:28

The ISO C++ standard way to do it is to #include <iomanip> and use io manipulators like std::setw. However, that said, those io manipulators are a real pain to use even for text, and are just about unusable for formatting numbers (I assume you want your dollar amounts to line up on the decimal, have the correct number of significant digits, etc.). Even for just plain text labels, the code will look something like this for the first part of your first line:

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

If you are able to use the Boost libraries, run (don't walk) and use the Boost.Format library instead. It is fully compatible with the standard iostreams, and it gives you all the goodness for easy formatting with printf/Posix formatting string, but without losing any of the power and convenience of iostreams themselves. For example, the first parts of your first two lines would look something like:

// using Boost.Format
cout << format("%-20s %-20s %-8s\n")  % "Artist" % "Title" % "Price";
cout << format("%-20s %-20s %8.2f\n") % "Merle" % "Blue" % 12.99;
Martin York

See also: Which C I/O library should be used in C++ code?

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

IO manipulators are what you need. setw, in particular. Here's an example from the reference page:

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

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

Justifying the field to the left and right is done with the left and right manipulators.

Also take a look at setfill. Here's a more complete tutorial on formatting C++ output with io manipulators.

The setw manipulator function will be of help here.

Another way to make column aligned is as follows:

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;

We should estimate maximum length of values for each column. In this case, values of "Artist" column should not exceed 20 characters and so on.

At the time you emit the very first line,

Artist  Title   Price   Genre   Disc    Sale    Tax Cash

to achieve "alignment", you have to know "in advance" how wide each column will need to be (otherwise, alignment is impossible). Once you do know the needed width for each column (there are several possible ways to achieve that depending on where your data's coming from), then the setw function mentioned in the other answer will help, or (more brutally;-) you could emit carefully computed number of extra spaces (clunky, to be sure), etc. I don't recommend tabs anyway as you have no real control on how the final output device will render those, in general.

Back to the core issue, if you have each column's value in a vector<T> of some sort, for example, you can do a first formatting pass to determine the maximum width of the column, for example (be sure to take into account the width of the header for the column, too, of course).

If your rows are coming "one by one", and alignment is crucial, you'll have to cache or buffer the rows as they come in (in memory if they fit, otherwise on a disk file that you'll later "rewind" and re-read from the start), taking care to keep updated the vector of "maximum widths of each column" as the rows do come. You can't output anything (not even the headers!), if keeping alignment is crucial, until you've seen the very last row (unless you somehow magically have previous knowledge of the columns' widths, of course;-).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!