格式化 C++ 控制台输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1449818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:01:24  来源:igfitidea点击:

Formatting C++ console output

c++formatting

提问by user40120

I've been trying to format the output to the console for the longest time and nothing is really happening. I've been trying to use as much of iomanipas I can and the ofstream&out functions.

我一直在尝试格式化输出到控制台的时间最长,但实际上什么也没发生。我一直在试图尽可能多的使用iomanip,我可以和ofstream&输出功能。

void list::displayByName(ostream& out) const
{
    node *current_node  = headByName;

    // I have these outside the loop so I don't write it every time.

    out << "Name\t\t" << "\tLocation" << "\tRating " << "Acre" << endl;
    out << "----\t\t" << "\t--------" << "\t------ " << "----" << endl;

    while (current_node)
    {
        out << current_node->item.getName() // Equivalent tabs don't work?
            << current_node->item.getLocation()
            << current_node->item.getAcres()
            << current_node->item.getRating()
            << endl;

        current_node = current_node->nextByName;
    }

    // The equivalent tabs do not work because I am writing names,
    // each of different length to the console. That explains why they
    // are not all evenly spaced apart.
}

Is their anything that I can use to get it all properly aligned with each other? The functions that I'm calling are self-explanatory and all of different lengths, so that don't align very well with each other.

我可以用它们来使它们彼此正确对齐吗?我正在调用的函数是不言自明的,并且长度各不相同,因此彼此之间不能很好地对齐。

I've tried just about everything in iomanip.

我已经尝试了iomanip.

采纳答案by Vargas

You can write a procedure that always print the same number of characters to standard output.

您可以编写一个过程,始终将相同数量的字符打印到标准输出。

Something like:

就像是:

string StringPadding(string original, size_t charCount)
{
    original.resize(charCount, ' ');
    return original;
}

And then use like this in your program:

然后在你的程序中像这样使用:

void list::displayByName(ostream& out) const
{
    node *current_node  = headByName;

    out << StringPadding("Name", 30)
        << StringPadding("Location", 10)
        << StringPadding("Rating", 10)
        << StringPadding("Acre", 10) << endl;
    out << StringPadding("----", 30)
        << StringPadding("--------", 10)
        << StringPadding("------", 10)
        << StringPadding("----", 10) << endl;

    while ( current_node)
    {
        out << StringPadding(current_node->item.getName(), 30)
            << StringPadding(current_node->item.getLocation(), 10)
            << StringPadding(current_node->item.getRating(), 10)
            << StringPadding(current_node->item.getAcres(), 10)
            << endl;
        current_node = current_node->nextByName;
    }
}

回答by AraK

Think of it like using Microsoft Excel :) You think of your stream as fields. So you set the width of the field first then you insert your text in that field. For example:

把它想象成使用 Microsoft Excel :) 您将您的流视为字段。因此,您首先设置字段的宽度,然后在该字段中插入文本。例如:

#include <iostream>
#include <iomanip>
#include <string>

int main()
{
    using namespace std;

    string firstName = "firstName",
            secondName = "SecondName",
            n = "Just stupid Text";
    size_t fieldWidth = n.size(); // length of longest text

    cout << setw(fieldWidth) << left << firstName << endl // left padding
         << setw(fieldWidth) << left << secondName << endl
         << setw(fieldWidth) << left << n << endl;

    cout << setw(fieldWidth) << right << firstName << endl // right padding
         << setw(fieldWidth) << right << secondName << endl
         << setw(fieldWidth) << right << n << endl;
}

......

......

alt text

替代文字

......

......

The field width means nothing but the width of the text + spaces. You could fillanything other than spaces:

字段宽度仅表示text + spaces. fill除了空格,你可以做任何事情:

string name = "My first name";
cout << setfill('_') << setw(name.size() + 10) << left << name;

.....

.....

output::
My first name__________

......

......

I think the best way is to figure out your format then, write a new formatter that does all what you want:

我认为最好的方法是弄清楚你的格式,然后编写一个新的格式化程序来完成你想要的所有事情:

#include <iostream>
#include <iomanip>
#include <string>

std::ostream& field(std::ostream& o)
{
    // usually the console is 80-character wide.
    // divide the line into four fields.
    return o << std::setw(20) << std::right;
}

int main()
{
    using namespace std;

    string firstName = "firstName",
            secondName = "SecondName",
            n = "Just stupid Text";
    size_t fieldWidth = n.size();

    cout << field << firstName << endl
         << field << secondName << endl
         << field << n << endl;
}

If you started thinking about parametrized manipulators, only that accept one intor longparameter are easy to implement, other types are really obscure if you are not familiar with streams in C++.

如果你开始考虑参数化操纵器,只有接受一个intlong参数的操纵器很容易实现,如果你不熟悉C++.

回答by Martin York

Boost has a format library that allows you to easily format the ourput like the old C printf() but with type safety of C++.

Boost 有一个格式库,它允许您像旧的 C printf() 一样轻松地格式化我们的输入,但具有 C++ 的类型安全性。

Remember that the old C printf() allowed you to specify a field width. This space fills the field if the output is undersized (note it does not cope with over-sized fields).

请记住,旧的 C printf() 允许您指定字段宽度。如果输出尺寸过小,则此空间会填充该字段(请注意,它无法处理过大的字段)。

#include <iostream>
#include <iomanip>
#include <boost/format.hpp>

struct X
{  // this structure reverse engineered from
   // example provided by 'Mikael Jansson' in order to make this a running example

    char*       name;
    double      mean;
    int         sample_count;
};
int main()
{
    X   stats[] = {{"Plop",5.6,2}};

    // nonsense output, just to exemplify

    // stdio version
    fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
            stats, stats->name, stats->mean, stats->sample_count);

    // iostream
    std::cerr << "at " << (void*)stats << "/" << stats->name
              << ": mean value " << std::fixed << std::setprecision(3) << stats->mean
              << " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
              << " samples\n";

    // iostream with boost::format
    std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
                % stats % stats->name % stats->mean % stats->sample_count;
}

回答by Adrian McCarthy

Give up on the tabs. You should be able to use io manipulators to set the field width, the fill character, and the format flag (to get left or right justification). Use the same values for the headings as you do for the data, and everything should come out nicely.

放弃标签。您应该能够使用 io 操作符来设置字段宽度、填充字符和格式标志(以获得左对齐或右对齐)。使用与数据相同的标题值,一切都应该很好。

Also beware that you've switched Rating and Acres in your example.

还要注意,您在示例中切换了 Rating 和 Acres。