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

idv4meu8  于 2022-12-15  发布在  其他
关注(0)|答案(6)|浏览(121)

我正在重构一些遗留代码,这些代码使用printf和长字符串(没有任何实际格式)来打印纯文本表格标题,概念上看起来像这样:

|  Table   |  Column  | Header  |

现在是这样生产的:

printf("|  Table   |  Column  | Header  |");

我想用代码生成上面的代码,其效果为1:

outputStream << "|" << std::setw(10) << std::center << "Table"
             << "|" << std::setw(10) << std::center << "Column"
             << "|" << std::setw(9) << std::center << "Header"
             << "|" << std::endl;

因为<iomanip>有流操纵器std::leftstd::rightstd::internal,但似乎没有任何std::center,所以不能编译。在标准C++库中是否已经有一种干净的方法来完成此操作,或者我必须手动计算必要的间距?
1尽管这段代码比C代码更冗长,但从长远来看,由于printf语句的数量和字符串中插入重复的数量,它不会太冗长,而且它还具有更好的可扩展性和可维护性。

p1tboqfb

p1tboqfb1#

在C++20中,你可以使用std::format来完成这个任务:

outputStream << std::format("|{:^10}|{:^10}|{:^9}|\n",
                            "Table", "Column", "Header");

输出:

|  Table   |  Column  | Header  |

同时,您可以使用the {fmt} librarystd::format基于。{fmt}还提供了print函数,使此操作更加简单和高效(godbolt):

fmt::print("|{:^10}|{:^10}|{:^9}|\n", "Table", "Column", "Header");

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

um6iljoc

um6iljoc2#

下面是一个helper类,它可以完成您想要的任务:

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

调用centered("String")就可以使用它,如下所示:

int main(int argc, char *argv[]) {
    std::cout << "|" << std::setw(10) << centered("Table")
              << "|" << std::setw(10) << centered("Column")
              << "|" << std::setw(9)  << centered("Header") << "|"
              << std::endl;
}
xdyibdwo

xdyibdwo3#

没有std::center操作器,恐怕你得自己动手了,你可以写一个helper函数来计算给定宽度和字符串的空格,以减少工作量。
下面是一个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, ' ');
}
ctzwtxfj

ctzwtxfj4#

恐怕你得手动操作了。但如果你使用字符串,这就不难了。比如:

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

应该可以。

7uzetpgm

7uzetpgm5#

这只适用于那些不需要对代码进行任何额外更改并且不包含任何新库的人,就像我一样。
上面给出的很多答案都需要新的helper类或额外的库,但是有一个简单的方法不需要任何额外的修改。你可以将宽度除以2,然后在要打印的元素的两侧添加setw()方法。作为问题的解决方案:

outputStream << "|" << std::setw(5) << "Table" << std::setw(5)
             << "|" << std::setw(5) << "Column" << std::setw(5)
             << "|" << std::setw(5) << "Header" << std::setw(5)
             << "|" << std::endl;

上面的代码将完成这项工作。
输出:

|  Table   |  Column  | Header  |
brtdzjyr

brtdzjyr6#

你可以使用NCURSES(#include<ncurses.h>)库...它有点时髦,你必须添加“-lncurses”到你的编译命令(gcc yourProgram.c/cpp -lncurses),它会工作,加上你可以做颜色和其他'酷'的东西(无论如何为CLI)。只要阅读手册,居中的东西是相当容易的。http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/

相关问题