【问题标题】:Quick formatted strings in C++C++ 中的快速格式化字符串
【发布时间】:2011-08-06 21:29:04
【问题描述】:

在构造 std::string 时,是否有一种快速、简单的方法来获得类似 sprintf 的格式?比如……

std::string foo("A number (%d) and a character (%c).\n", 18, 'a');

【问题讨论】:

  • 看看我的解决方案。那是 C++ 风格的解决方案。不依赖于涉及%d%c 的C 样式格式字符串,如boost。

标签: c++ string formatting


【解决方案1】:

未内置在字符串的构造函数中,但您可能想查看boost format。它是一种更安全的 sprintf 风格的字符串格式。有了它,您至少可以做到这一点:

std::string foo = 
    boost::str(boost::format("A number (%d) and a character (%c)\n") % 18 % 'a');

【讨论】:

  • 放置 uint8_t 而不是文字 18 — 瞧,您的 Boost 输出完全被破坏了:您将收到两个字符,而不是带有字符的数字。
【解决方案2】:

我写了一个stringbuilder 类,你可以使用它,我认为它比boost::format 更好,因为它不像stringbuilder 不使用像%d%c 这样的C 样式格式字符串。等等

stringbuilder 可以通过以下方式帮助您:

std::string s=stringbuilder() << "A number " << 18 <<" and a character " <<'a';

stringbuilder的实现很简单:

struct stringbuilder
{
   std::stringstream ss;
   template<typename T>
   stringbuilder & operator << (const T &data)
   {
        ss << data;
        return *this;
   }
   operator std::string() { return ss.str(); }
};

ideone 演示:http://ideone.com/J9ALB


我刚刚写了以下博客,描述了stringbuilder 的许多不同使用方式。

【讨论】:

  • +1 感谢分享 :) 但我更喜欢 C 风格的格式化语法。我个人发现“这是我的字符串,替换适当的标记”的方法来格式化比一块一块地组装它们更舒服。
  • @Santiago: 但是你知道 C-Style 格式不安全,这就是 C++ 不使用它们的原因,而是提出了 coutcin 以及其他流类是安全的。
  • @Nawaz:这也是开发 boost::format 的原因,它具有类似 printf 的格式,并且与 iostream 一样安全。
  • @Nawaz:一旦您编写了国际化软件,您就会爱上 C 格式的风格(尽管使用安全的方法...),因为它能够在最终翻译中移动动态位。 IOStream 支持方面,它们让您为此付出高昂的代价,但它对国际化毫无帮助:/
  • @Nawaz:假设您想包含一个形容词,供用户选择。在法语中,你有句子printf("J'ai vu des oiseaux %s", adjective);,它可以用于流:os &lt;&lt; "J'ai vu des oiseaux " &lt;&lt; adjective。然而,在英语中,os &lt;&lt; "I have seen birds " &lt;&lt; adjective 是不正确的。你需要printf("I have seen %s birds", adjective)。句子的拆分完全不同。在这种情况下,您需要 C 样式的流式格式。 (或者你需要为每种语言更改流,但这太疯狂了,看看 gettext 看看资源是如何处理的)
【解决方案3】:

fmt library 提供了一个安全的sprintf 实现,它返回一个字符串:

std::string foo = fmt::sprintf("A number (%d) and a character (%c).\n", 18, 'a');

这个库还支持 Python 的 str.format 语法:

std::string foo = fmt::format("A number ({}) and a character ({}).\n", 18, 'a');

它的目的类似于 Boost 格式,但 much faster,非常小,除了标准 C++ 库之外没有外部依赖项。

免责声明:我是这个库的作者。

【讨论】:

    【解决方案4】:

    这个怎么样,直接用printf:

    #include <stdio.h> 
    #include <stdarg.h> 
    
    std::string format(const char *fmt, ...) 
    { 
        va_list ap; 
        va_start(ap, fmt); 
    
        const size_t SIZE = 512; 
        char buffer[SIZE] = { 0 }; 
        vsnprintf(buffer, SIZE, fmt, ap); 
    
        va_end(ap); 
    
        return std::string(buffer); 
    } 
    

    【讨论】:

    • 最好查看vsnprintf 返回值来分配大小合适的缓冲区,而不是在 512 个字符处将其截断。或者在 Linux 上使用 asprintf。另外,请使用gcc-style function attributes,这样您仍然可以在参数上获得一些类型安全性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 2013-07-09
    • 2021-05-09
    • 2016-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多