【问题标题】:How can I format a std::string using a collection of arguments?如何使用参数集合格式化 std::string?
【发布时间】:2011-02-22 09:43:31
【问题描述】:

是否可以格式化std::string 传递一组参数?

目前我正在以这种方式格式化字符串:

string helloString = "Hello %s and %s";
vector<string> tokens; //initialized vector of strings
const char* helloStringArr = helloString.c_str();
char output[1000];
sprintf_s(output, 1000, helloStringArr, tokens.at(0).c_str(), tokens.at(1).c_str());

但是向量的大小是在运行时确定的。是否有与sprintf_s 类似的函数,它接受参数集合并格式化std::string/char*?我的开发环境是 MS Visual C++ 2010 Express。

编辑: 我想实现类似的目标:

sprintf_s(output, 1000, helloStringArr, tokens);

【问题讨论】:

标签: c++ string-formatting stdstring variadic-functions


【解决方案1】:

实现类 sprintf 功能的最 C++ 风格的方法是使用 stringstreams

这是一个基于您的代码的示例:

#include <sstream>

// ...

std::stringstream ss;
std::vector<std::string> tokens;
ss << "Hello " << tokens.at(0) << " and " << tokens.at(1);

std::cout << ss.str() << std::endl;

很方便,不是吗?

当然,您可以充分利用 IOStream 操作来替换各种 sprintf 标志,请参阅此处http://www.fredosaurus.com/notes-cpp/io/omanipulators.html 以供参考。

一个更完整的例子:

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

int main() {
  std::stringstream s;
  s << "coucou " << std::setw(12) << 21 << " test";

  std::cout << s.str() << std::endl;
  return 0;
}

打印:

coucou           21 test

编辑

正如 OP 所指出的,这种处理方式不允许使用可变参数,因为没有预先构建的“模板”字符串允许流遍历向量并根据占位符插入数据。

【讨论】:

  • 谢谢,但我仍然看不到如何将向量作为参数传递而不一一获取值。我需要类似的东西:sprintf_s(output, 1000, helloStringArr, tokens);
  • C++ 风格的方式仍然是将标记添加到字符串流中,而不是先构建标记集合,然后再次尝试重新格式化它们。如果我们知道我们在做什么,而不是我们应该如何做,这可能会有所帮助。 :-)
  • @Bo:所以 C++ 的方式是不使用格式字符串,而放弃所有优点,例如可读性 ;) 或基本的国际化? (您必须提供给流的字符串片段基本上无法进行有意义的翻译)
  • @visitor:可读性也许不是格式字符串的真正优势。 :-)。如果您不考虑项目的顺序可能会受到语言的影响,或者使用的短语取决于项目的数量,那么国际化也将是非常基本的。
【解决方案2】:

您可以使用Boost.Format 库来做到这一点,因为您可以一一提供参数。

这实际上使您能够实现您的目标,这与 printf 系列完全不同,您必须一次传递所有参数(即您需要手动访问容器中的每个项目)。

例子:

#include <boost/format.hpp>
#include <string>
#include <vector>
#include <iostream>
std::string format_range(const std::string& format_string, const std::vector<std::string>& args)
{
    boost::format f(format_string);
    for (std::vector<std::string>::const_iterator it = args.begin(); it != args.end(); ++it) {
        f % *it;
    }
    return f.str();
}

int main()
{
    std::string helloString = "Hello %s and %s";
    std::vector<std::string> args;
    args.push_back("Alice");
    args.push_back("Bob");
    std::cout << format_range(helloString, args) << '\n';
}

您可以从这里开始工作,使其模板化等。

请注意,如果向量不包含确切数量的参数,它会引发异常(请参阅文档)。您需要决定如何处理这些问题。

【讨论】:

  • 问题是要求 std::string 不是 boost。
【解决方案3】:

如果您想避免手动处理输出缓冲区,boost::format 库可能会很有趣。

至于将纯向量作为输入,如果tokens.size()&lt;2,您希望发生什么?在任何情况下,您都不必确保向量足够大以索引元素 0 和 1 吗?

【讨论】:

  • 我检查了这个库,但没有找到将格式化参数作为一组参数传递的方法。
猜你喜欢
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 2017-03-23
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
相关资源
最近更新 更多