如何轻松地在 C++ 中格式化我的数据表?

Posted

技术标签:

【中文标题】如何轻松地在 C++ 中格式化我的数据表?【英文标题】:How can I easily format my data table in C++? 【发布时间】:2013-02-08 03:21:25 【问题描述】:

我不确定,但我想我记得在 Java 中有一些东西可以指定字符串或数字从窗口左侧开始的距离......

如何轻松格式化表格? 我有这个(使用 setw):

Bob Doe     10.96      7.61     14.39      2.11     47.30     14.21     44.58      5.00     60.23
Helen City     10.44      7.78     16.27      1.99     48.92     13.93     53.79      5.00     70.97
Joe Green     10.90      7.33     14.49      2.05     47.91     14.15     44.45      4.70     73.98

理想情况下希望:

Bob           Doe        BLR  10.96   7.61  14.39   2.11  47.30  14.21  44.58   5.00  60.23  4:27.47
Helen         City       CUB  10.90   7.33  14.49   2.05  47.91  14.15  44.45   4.70  73.98  4:29.17
Joe           Green      USA  10.44   7.78  16.27   1.99  48.92  13.93  53.79   5.00  70.97  5:06.59

是唯一的计算方法吗?还是有什么更神奇更简单的方法?

【问题讨论】:

您应该可以使用setw 执行此操作。你说你正在使用setw,但你没有说明如何使用。 【参考方案1】:

在 C++ 中,您可以使用三个函数来帮助您做您想做的事。有定义在<iomanip>. - setw() 帮助您定义输出的宽度。 - setfill() 用您想要的字符填充其余部分(在您的情况下为“ ”)。 - left(或右)允许您定义对齐方式。

这是编写第一行的代码:

#include <iostream>
#include <iomanip>

using namespace std;

int main() 
    const char separator    = ' ';
    const int nameWidth     = 6;
    const int numWidth      = 8;

    cout << left << setw(nameWidth) << setfill(separator) << "Bob";
    cout << left << setw(nameWidth) << setfill(separator) << "Doe";
    cout << left << setw(numWidth) << setfill(separator) << 10.96;
    cout << left << setw(numWidth) << setfill(separator) << 7.61;
    cout << left << setw(numWidth) << setfill(separator) << 14.39;
    cout << left << setw(numWidth) << setfill(separator) << 2.11;
    cout << left << setw(numWidth) << setfill(separator) << 47.30;
    cout << left << setw(numWidth) << setfill(separator) << 14.21;
    cout << left << setw(numWidth) << setfill(separator) << 44.58;
    cout << left << setw(numWidth) << setfill(separator) << 5.00;
    cout << left << setw(numWidth) << setfill(separator) << 60.23;
    cout << endl;

    cin.get();

编辑: 为了减少代码,你可以使用模板函数:

template<typename T> void printElement(T t, const int& width)

    cout << left << setw(width) << setfill(separator) << t;

你可以这样使用:

printElement("Bob", nameWidth);
printElement("Doe", nameWidth);
printElement(10.96, numWidth);
printElement(17.61, numWidth);
printElement(14.39, numWidth);
printElement(2.11, numWidth);
printElement(47.30, numWidth);
printElement(14.21, numWidth);
printElement(44.58, numWidth);
printElement(5.00, numWidth);
printElement(60.23, numWidth);
cout << endl;

【讨论】:

永远不要使用system("PAUSE"),因为据说它可能会导致一些未定义的效果。相反,请致电cin.get(),这将更加跨平台。【参考方案2】:

以下是我用来以有组织的表格形式显示数据的各种函数,以及一个演示可能使用场景的示例。

由于这些函数使用字符串流,它们的速度不如其他解决方案快,但对我来说这并不重要——计算瓶颈在别处。

使用字符串流的一个优点是函数会更改它们自己(内部范围)字符串流的精度,而不是更改静态 cout 精度。因此,您永远不必担心无意中修改精度会持续影响代码的其他部分。


显示任意精度

这个prd 函数(“print double”的缩写)简单地打印一个具有指定精度的双精度值。

/* Convert double to string with specified number of places after the decimal. */
std::string prd(const double x, const int decDigits) 
    stringstream ss;
    ss << fixed;
    ss.precision(decDigits); // set # places after decimal
    ss << x;
    return ss.str();

以下只是一个变体,它允许您在数字左侧指定一个空格填充。这有助于显示表格。

/* Convert double to string with specified number of places after the decimal
   and left padding. */
std::string prd(const double x, const int decDigits, const int width) 
    stringstream ss;
    ss << fixed << right;
    ss.fill(' ');        // fill space around displayed #
    ss.width(width);     // set  width around displayed #
    ss.precision(decDigits); // set # places after decimal
    ss << x;
    return ss.str();

中心对齐功能

此函数只是将文本居中对齐,左右填充空格,直到返回的字符串与指定的宽度一样大。

/*! Center-aligns string within a field of width w. Pads with blank spaces
    to enforce alignment. */
std::string center(const string s, const int w) 
    stringstream ss, spaces;
    int padding = w - s.size();                 // count excess room to pad
    for(int i=0; i<padding/2; ++i)
        spaces << " ";
    ss << spaces.str() << s << spaces.str();    // format with padding
    if(padding>0 && padding%2!=0)               // if odd #, add 1 space
        ss << " ";
    return ss.str();

表格输出示例

因此,我们可以使用上面的prdcenter 函数以下列方式输出表格。

代码:

std::cout << center("x",10)       << " | "
          << center("x^2",10)     << " | "
          << center("(x^2)/8",10) << "\n";

std::cout << std::string(10*3 + 2*3, '-') << "\n";

for(double x=1.5; x<200; x +=x*2) 
    std::cout << prd(x,1,10)       << " | "
              << prd(x*x,2,10)     << " | "
              << prd(x*x/8.0,4,10) << "\n";

将打印表格:

    x      |    x^2     |  (x^2)/8  
------------------------------------
       1.5 |       2.25 |     0.2812
       4.5 |      20.25 |     2.5312
      13.5 |     182.25 |    22.7812
      40.5 |    1640.25 |   205.0312
     121.5 |   14762.25 |  1845.2812

右对齐和左对齐功能

当然,您可以轻松地构造 center 函数的变体,该函数可以右对齐或左对齐,并添加填充空间以填充所需的宽度。以下是这样的功能:

/* Right-aligns string within a field of width w. Pads with blank spaces
   to enforce alignment. */
string right(const string s, const int w) 
    stringstream ss, spaces;
    int padding = w - s.size();                 // count excess room to pad
    for(int i=0; i<padding; ++i)
        spaces << " ";
    ss << spaces.str() << s;                    // format with padding
    return ss.str();


/*! Left-aligns string within a field of width w. Pads with blank spaces
    to enforce alignment. */
string left(const string s, const int w) 
    stringstream ss, spaces;
    int padding = w - s.size();                 // count excess room to pad
    for(int i=0; i<padding; ++i)
        spaces << " ";
    ss << s << spaces.str();                    // format with padding
    return ss.str();

我敢肯定有很多更优雅的方法来做这种事情——当然还有更简洁的方法。但这就是我所做的。很适合我。

【讨论】:

对于一些法语口音的 center() 中 utf8 的填充错误,您可以使用此处给出的小代码进行脏修复:***.com/a/4063229/3066309 // utf8 stuff const char *c_str = s.c_str();国际长度 = 0; while (*c_str) // 只计算真正的 utf8 char len += (*c_str++ & 0xc0) != 0x80; padding += s.size() - len;【参考方案3】:

只需使用 sprintf 和 format specifiers 来格式化字段。你也可以使用 MFC CString

#include <iostream>
#include "stdio.h"

using namespace std;

int main()

    char buf[256];
    char pattern[]  = "%10s %10s     %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f";
    sprintf(buf, pattern, "Bob",  "Doe",     10.96,      7.61,     14.39,      2.11,     47.30,     14.21,     44.58,      5.00,     60.23);
    cout << buf << endl;
    sprintf(buf, pattern, "Helen", "City",     10.44,      7.78,     16.27,      1.99,     48.92,     13.93,     53.79,      5.00,     70.97);
    cout << buf << endl;
    sprintf(buf, pattern, "Joe", "Green",     10.90,      7.33,     14.49,      2.05,     47.91,     14.15,     44.45,      4.70,     73.98);
    cout << buf << endl;

【讨论】:

【参考方案4】:

你可以做这样的事情来简化这个过程。

#include <iomanip>
#include <iostream>

struct TableFormat 
    int width;
    char fill;
    TableFormat(): width(14), fill(' ') 
    template<typename T>
    TableFormat& operator<<(const T& data) 
        std::cout << data << std::setw(width) << std::setfill(fill);
        return *this;
    
    TableFormat& operator<<(std::ostream&(*out)(std::ostream&)) 
        std::cout << out;
        return *this;
    
;

int main() 
    TableFormat out;
    out << "Bob" << "Doe";
    out.width = 8;
    out << "BLR" << 10.96 << 7.61 << 14.39 << 2.11 << 47.30;

哪个会打印出来(在我的情况下很可怕,但它在一定程度上是“可定制的”):

Bob           Doe           BLR   10.96    7.61   14.39    2.11    47.3

代码是不言自明的,它只是对std::cout 的包装,让您可以更轻松地进行繁琐的调用,operator&lt;&lt; 的第二个重载是允许您发送std::endl..

【讨论】:

【参考方案5】:

假设您要将输出格式化为类似于表格,您需要的是 I/O manipulators。 您可以使用 setw() 操纵器设置输出宽度,使用 setfill() 设置填充字符。

【讨论】:

【参考方案6】:

考虑一个例子:

string firstname = "Bob";
string lastname = "Doe";
string country = "BLR";
float f1 = 10.96f, f2=7.61f, f3=14.39f, f4=2.11f, f5=47.30f, f6=14.21f, f7=44.58f, f8=5.00f, f9=60.23f;
string time = "4:27.47";
cout << setw(12) << firstname << set(12) << lastname;
cout << setw(5) << country << setprecision(2) << f1 << setprecision(2) << f2 << setprecision(2) << f3..
    在打印字符串时使用setw()设置宽度 使用setprecision 设置浮点值的精度 阅读MSDN

【讨论】:

【参考方案7】:

我不确定你写了什么,所以我看不出有什么问题,但你可以使用 std::setw 得到你想要的结果:

#include <iostream>
#include <iomanip>

int main() 
   std::cout << std::left << std::setw(20) << "BoB" << std::setw(20) << 123.456789 << '\n';
   std::cout << std::left << std::setw(20) << "Richard" << std::setw(20) << 1.0 << '\n';

http://ideone.com/Iz5RXr

【讨论】:

以上是关于如何轻松地在 C++ 中格式化我的数据表?的主要内容,如果未能解决你的问题,请参考以下文章

如何像处理语言一样轻松地在 c++ 中为 windows 和 linux 绘制原始像素? [关闭]

如何从 DataGrip 导出/导入数据源?

如何轻松地在 PHP 中缩小 JS ......或其他

通过多个 .xaml 文件进行数据绑定

如何找到我的 C++ 应用程序正在使用的标头? [复制]

C++:方法中的字符串成员别名