By user69514


2010-03-21 04:43:01 8 Comments

Is there a way to align text when printing using std::cout? I'm using tabs, but when the words are too big they won't be aligned anymore.

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 comments

@Nguyen 2014-03-12 18:37:33

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.

@Herb Sutter 2010-03-21 05:41:09

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;

@dreamlax 2010-03-29 09:47:12

Boost.Format looks great. Straightforward printf-style formatting with type-safety.

@Donal Fellows 2010-05-02 11:50:02

Positional formats too, which is great since it means you can pull them from a localization file.

@Martin York 2010-03-21 09:13:41

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

@Alex Martelli 2010-03-21 04:57:50

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;-).

@Eli Bendersky 2010-03-21 04:54:29

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.

@codaddict 2010-03-21 04:44:58

The setw manipulator function will be of help here.

@Matthieu M. 2010-03-21 14:48:56

You should also mention the left and right which allows to specify the alignment and setfill which allows to specify with which character completing (space by default).

Related Questions

Sponsored Content

25 Answered Questions

[SOLVED] What is the "-->" operator in C++?

15 Answered Questions

[SOLVED] What is the effect of extern "C" in C++?

10 Answered Questions

1 Answered Questions

[SOLVED] The Definitive C++ Book Guide and List

  • 2008-12-23 05:23:56
  • grepsedawk
  • 2388131 View
  • 4243 Score
  • 1 Answer
  • Tags:   c++ c++-faq

28 Answered Questions

[SOLVED] Easiest way to convert int to string in C++

40 Answered Questions

19 Answered Questions

[SOLVED] How can I profile C++ code running on Linux?

  • 2008-12-17 20:29:24
  • Gabriel Isenberg
  • 529194 View
  • 1834 Score
  • 19 Answer
  • Tags:   c++ linux profiling

9 Answered Questions

49 Answered Questions

[SOLVED] Vertically align text to top within a UILabel

16 Answered Questions

[SOLVED] 'printf' vs. 'cout' in C++

Sponsored Content