C++字符串格式化如Python中的"{}".format。

26

我希望找到一种快速整洁的方式以漂亮的表格格式打印,使单元格正确对齐。

C++中是否有一种方便的方法可以创建特定长度的子字符串字符串,类似于Python format的功能?

"{:10}".format("some_string")

3
请查看 stdio.h 中的 printf 函数族。 - Grifplex
6个回答

50
在C++20中,您可以使用{{link1:std::format}},它将Python样式的格式应用到C++中:
auto s = std::format("{:10}", "some_string");

在它广泛可用之前,您可以使用开源的{fmt}格式化库std::format 基于此。

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


4
好的。不过很遗憾,实际上当我们转换到C++20时,可能已经是2025年了。 - chrise
6
您可以在此期间使用 {fmt} =)。 - vitaut
Python支持这种写法:str = f'{v1} xxx {v2} xxx {v3}'。现代C++是否支持类似的写法? - kgflying
没有,但是有一个提案建议将字符串插值添加到C++中。 - vitaut

29

试一下这个https://github.com/fmtlib/fmt

fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");

5
这个库很实用,但对于可以用几行代码完成的事情来说可能有些过度使用,并且还有许可限制。 - Damien
是的,我更喜欢使用#ifdef禁用一些功能,例如颜色。 - mattn
2
我不认为使用库是一种“快速而整洁”的方式。 - Aldarrion
@Damien,许可证限制是什么? - wonko realtime
你必须在你的软件中包含MIT许可证,虽然这个许可证相当宽容,但也有一些缺点。https://softwareengineering.stackexchange.com/questions/264700/paid-software-includes-mit-licensed-library-does-that-put-my-app-under-mit-too - Damien

7
你有很多选择。例如使用流。
source.cpp
  std::ostringstream stream;
  stream << "substring";
  std::string new_string = stream.str();

4

0
你可以快速编写一个简单的函数来返回固定长度的字符串。
我们认为str字符串以 null 结尾,buf 在调用函数之前已经定义好。
void format_string(char * str, char * buf, int size)
{
    for (int i=0; i<size; i++)
        buf[i] = ' '; // initialize the string with spaces

    int x = 0;
    while (str[x])
    {
        if (x >= size) break;
        buf[x] = str[x]; // fill up the string
    }

    buf[size-1] = 0; // termination char
}

用作

char buf[100];
char str[] = "Hello";
format_string(str, buf, sizeof(buf));
printf(buf);

-1

如果您无法像上面提到的那样使用 fmt,则最好的方法是使用一个格式化的包装类。以下是我曾经做过的:

#include <iomanip>
#include <iostream>

class format_guard {
  std::ostream& _os;
  std::ios::fmtflags _f;

public:
  format_guard(std::ostream& os = std::cout) : _os(os), _f(os.flags()) {}
  ~format_guard() { _os.flags(_f); }
};

template <typename T>
struct table_entry {
  const T& entry;
  int width;
  table_entry(const T& entry_, int width_)
      : entry(entry_), width(static_cast<int>(width_)) {}
};

template <typename T>
std::ostream& operator<<(std::ostream& os, const table_entry<T>& e) {
  format_guard fg(os);
  return os << std::setw(e.width) << std::right << e.entry; 
}

然后您可以将其用作std::cout << table_entry("some_string", 10)。 您可以根据需要调整table_entry。 如果您没有类模板参数推断,可以实现make_table_entry函数进行模板类型推断。

format_guard是必需的,因为std::ostream上的某些格式选项是粘性的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接