C++ 使用C+中的流操纵器在固定宽度字段中居中显示文本+;

C++ 使用C+中的流操纵器在固定宽度字段中居中显示文本+;,c++,string,stringstream,ostream,manipulators,C++,String,Stringstream,Ostream,Manipulators,我正在重构一些旧式代码,它使用长字符串(无任何实际格式)的printf打印纯文本表格标题,从概念上看如下所示: | Table | Column | Header | printf("| Table | Column | Header |"); 目前正在生产的产品如下: | Table | Column | Header | printf("| Table | Column | Header |"); 我想用1的代码生成上面的代码: out

我正在重构一些旧式代码,它使用长字符串(无任何实际格式)的
printf
打印纯文本表格标题,从概念上看如下所示:

|  Table   |  Column  | Header  |
printf("|  Table   |  Column  | Header  |");
目前正在生产的产品如下:

|  Table   |  Column  | Header  |
printf("|  Table   |  Column  | Header  |");
我想用1的代码生成上面的代码:


outputStream没有
std::center
操纵器。恐怕你得自己做。您可以编写一个helper函数来计算给定宽度和字符串的空格,以减少工作量

下面是一个助手函数的示例。它需要一些工作来提高效率,等等

string helper(int width, const string& str) {
    int len = str.length();
    if(width < len) { return str; }

    int diff = width - len;
    int pad1 = diff/2;
    int pad2 = diff - pad1;
    return string(pad1, ' ') + str + string(pad2, ' ');
}
string助手(int-width、const-string和str){
int len=str.length();
if(宽度
恐怕您必须手动操作。但事实并非如此 如果你用琴弦演奏,那就很难了。比如:

std::string
centered( std::string const& original, int targetSize )
{
    assert( targetSize >= 0 );
    int padding = targetSize - checked_cast<int>( original.size() );
    return padding > 0
        ? std::string( padding / 2, ' ' ) 
            + original
            + std::string( targetSize - (padding / 2), ' ' )
        : original;
}
std::string
居中(标准::字符串常量和原始值,int targetSize)
{
断言(targetSize>=0);
int padding=targetSize-checked_cast(original.size());
返回填充>0
?标准::字符串(填充/2'')
+原创的
+字符串(targetSize-(填充/2),“”)
:原件;
}

应该这样做。

下面是一个帮助器类,它可以实现您想要的功能:

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

template<typename charT, typename traits = std::char_traits<charT> >
class center_helper {
    std::basic_string<charT, traits> str_;
public:
    center_helper(std::basic_string<charT, traits> str) : str_(str) {}
    template<typename a, typename b>
    friend std::basic_ostream<a, b>& operator<<(std::basic_ostream<a, b>& s, const center_helper<a, b>& c);
};

template<typename charT, typename traits = std::char_traits<charT> >
center_helper<charT, traits> centered(std::basic_string<charT, traits> str) {
    return center_helper<charT, traits>(str);
}

// redeclare for std::string directly so we can support anything that implicitly converts to std::string
center_helper<std::string::value_type, std::string::traits_type> centered(const std::string& str) {
    return center_helper<std::string::value_type, std::string::traits_type>(str);
}

template<typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& s, const center_helper<charT, traits>& c) {
    std::streamsize w = s.width();
    if (w > c.str_.length()) {
        std::streamsize left = (w + c.str_.length()) / 2;
        s.width(left);
        s << c.str_;
        s.width(w - left);
        s << "";
    } else {
        s << c.str_;
    }
    return s;
}

你可以使用NCURSES图书馆。。。这有点奇怪,您必须将“-L NCURSES”添加到编译命令(g++-L NCURSES yourProgram.cpp)中,而且它可以工作,而且您还可以使用颜色和其他“酷”的东西[COLL for CLI]。 只要阅读手册,居中的东西是很容易的。

在C++20中,您可以使用来执行以下操作:

outputStream << std::format("|{:^10}|{:^10}|{:^9}|\n",
                            "Table", "Column", "Header");
同时,您可以使用,
std::format
基于。{fmt}还提供了
print
函数,该函数使这项工作更简单、更高效():


免责声明:我是{fmt}和C++20
std::format

啊!!我喜欢这样。非常聪明。这只适用于C++0x吗?在MSVS2010中,我得到“默认模板参数只允许在类模板上使用”。根据这个已经在C++0x中修复。@jep:奇怪。它在叮当声中工作得非常好。在第24行,尝试删除默认模板参数,使其仅为
template
。这行吗?@jep:如果你把那行改成
返回中心(str)会怎么样?另外,我刚刚编辑了答案,删除了第24行的默认模板参数。它实际上什么都没做,我不太清楚为什么我一开始就把它放在那里,可能只是因为我把模板参数与
center\u helper
类匹配。对不起-诅咒是旗帜。我已经好几年没使用网络课程了
fmt::print("|{:^10}|{:^10}|{:^9}|\n", "Table", "Column", "Header");