69

有没有办法在使用打印时对齐文本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
4

8 回答 8

136

执行此操作的 ISO C++ 标准方法是#include <iomanip>使用 io 操作符,例如std::setw. 然而,也就是说,那些 io 操纵器即使用于文本也很痛苦,并且几乎无法用于格式化数字(我假设您希望您的美元金额在小数点上排列,具有正确的有效位数等.)。即使对于纯文本标签,第一行的第一部分代码也会如下所示:

// 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库。它与标准 iostream 完全兼容,它为您提供了使用 printf/Posix 格式化字符串轻松格式化的所有优点,但又不会失去 iostream 本身的任何功能和便利性。例如,前两行的第一部分看起来像:

// using Boost.Format
cout << format("%-20s %-20s %-8s\n")  % "Artist" % "Title" % "Price";
cout << format("%-20s %-20s %8.2f\n") % "Merle" % "Blue" % 12.99;
于 2010-03-21T05:41:09.760 回答
11

另请参阅:应在 C++ 代码中使用哪个 CI/O 库?

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;
}
于 2010-03-21T09:13:41.223 回答
11

另一种使列对齐的方法如下:

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 个字符,依此类推。

于 2014-03-12T18:37:33.020 回答
10

IO 操纵器是您所需要的。特别是setw。以下是参考页面中的示例:

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

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

left使用和right操纵器将字段向左和向右对齐。

还要看看setfill这是关于使用 io manipulators 格式化 C++ 输出的更完整教程。

于 2010-03-21T04:54:29.313 回答
10

setw操纵器功能将在这里有所帮助。

于 2010-03-21T04:44:58.200 回答
4

在你发出第一行的时候,

Artist  Title   Price   Genre   Disc    Sale    Tax Cash

要实现“对齐”,您必须“提前”知道每列需要多宽(否则,对齐是不可能的)。一旦您知道每列所需的宽度(根据数据的来源,有几种可能的方法可以实现这一点),那么setw另一个答案中提到的函数将有所帮助,或者(更残酷;-)您可以仔细发出计算出的额外空格数(肯定是笨重的)等。我不建议使用制表符,因为通常您无法真正控制最终输出设备将如何呈现这些空格。

回到核心问题,vector<T>例如,如果您有某种类型的每一列的值,您可以执行第一次格式化传递以确定列的最大宽度,例如(请务必考虑当然,列的标题也是如此)。

如果您的行是“一个接一个”的,并且对齐至关重要,则必须在行进入时对其进行缓存或缓冲(如果它们适合,则在内存中,否则在稍后将“倒带”的磁盘文件上并从头开始重新读取),注意随着行的到来保持更新“每列的最大宽度”的向量。你不能输出任何东西(甚至是标题!),如果保持对齐是至关重要的,直到你看到最后一行(除非你以某种方式神奇地预先知道了列的宽度;-)。

于 2010-03-21T04:57:50.877 回答
1

C++20std::format选项<^>

根据https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification,以下内容应该成立:

// left: "42    "
std::cout << std::format("{:<6}", 42);

// right: "    42"
std::cout << std::format("{:>6}", 42);

// center: "  42  "
std::cout << std::format("{:^6}", 42);

更多信息:std::string 格式,如 sprintf

于 2020-09-24T14:23:19.660 回答
0

不使用“复杂”函数的最简单方法是手动格式化:

一个例子:

  std::cout << std::setprecision(10)
            << "integral of sin(x) from x = 0 to x = pi" << '\n'
            << "approximate: " << integrate(a, b, nbins) << '\n'
            << "exact:       " << 2.0                    << '\n';
于 2022-01-28T21:01:33.277 回答