2010-03-21 67 views
54

有沒有辦法使用std::cout打印時對齊文本?我正在使用標籤,但是當文字太大時,它們將不再對齊。C++對齊打印時的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 
+2

下面的回答允許指定列的寬度。請注意,這需要您知道上限(例如數據庫約束)或預先計算(這可能意味着在實際開始打印之前解析整個結構)。第二個,雖然有必要,但當然要慢:) –

回答

7

setw操縱器功能在這裏會有所幫助。

+3

你還應該提到'left'和'right',它允許指定對齊和'setfill',它允許指定哪個字符完成(默認空間)。 –

8

IO操縱是你所需要的。特別是setw。下面是引用頁面的例子:

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

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

護短領域的左側和右側與leftright機械手完成。

而且看一看setfill。以下是關於formatting C++ output with io manipulators的更完整教程。

4

在你發出的第一行的時候,

Artist Title Price Genre Disc Sale Tax Cash 

實現「定位」,你必須知道「提前」每列將有多寬需(否則,對齊是不可能的) 。一旦你知道每個列的寬度需要(有幾種可能的方式來實現,取決於您的數據的來自),然後在其他的答案中提到的setw功能將幫助,或者(更殘酷,你;-)可能會發出精心計算的額外空間(笨拙的,肯定的)等等。我不推薦標籤,因爲您無法真正控制最終輸出設備如何渲染這些空間。例如,如果某列的vector<T>中的每個列的值都有,例如,可以執行第一個格式化傳遞來確定列的最大寬度,例如(確保將其放入當然也要考慮列標題的寬度)。

如果你的行來了「一個接一個」,和對齊是至關重要的,你必須緩存或因爲他們進來(在內存中,如果他們符合緩存行,否則在磁盤文件,你會稍後「倒帶」並從頭開始重讀),注意隨着行的出現,保持「每列最大寬度」的向量更新。你不能輸出任何東西(甚至沒有頭文件!),如果保持對齊是至關重要的,直到你看到最後一行(除非你奇蹟般地知道了列的寬度,當然;-)。

112

ISO C++標準的做法是到#include <iomanip>並使用像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 libraries,運行(不走),並使用代替Boost.Format庫。它與標準的iostreams完全兼容,並且它爲您提供了使用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; 
+5

Boost.Format真的很不錯:) –

+2

'Boost.Format'看起來不錯。簡單的'printf'格式與類型安全。 – dreamlax

+4

位置格式也很棒,因爲這意味着您可以將它們從本地化文件中提取出來。 –

9

參見: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; 
} 
5

另一種方法,使對齊列如下:

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個字符,依此類推。