【问题标题】:Formatting C++ console output格式化 C++ 控制台输出
【发布时间】:2010-11-29 19:21:20
【问题描述】:

我一直在尝试将输出格式化到控制台的最长时间,但实际上并没有发生任何事情。我一直在尝试尽可能多地使用iomanipofstream& out 函数。

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

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

我已经尝试了iomanip 中的所有内容。

【问题讨论】:

    标签: c++ formatting


    【解决方案1】:

    把它想象成使用 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;
    }
    

    ......

    ......

    字段宽度仅表示text + spaces 的宽度。你可以fill除空格以外的任何东西:

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

    .....

    output::
    My first name__________
    

    ......

    我认为最好的方法是找出你的格式,然后编写一个新的格式化程序来满足你的所有需求:

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

    如果你开始考虑参数化操纵器,只有接受一个intlong 参数很容易实现,如果你不熟悉C++ 中的流,其他类型真的很模糊。

    【讨论】:

    • +1 用于标准 io 操纵器 (setw & al),+1 用于定义自定义 iomanip,-1 用于 Excel
    • 而且您还可以限制要打印的字符串的大小,以防万一您有大字符串(例如完整的名称)
    【解决方案2】:

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

    请记住,旧的 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;
    }
    

    【讨论】:

      【解决方案3】:

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

      另外请注意,您在示例中切换了 Rating 和 Acres。

      【讨论】:

        【解决方案4】:

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

        类似:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-19
          • 1970-01-01
          • 2017-02-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-28
          相关资源
          最近更新 更多