如何使用参数集合格式化std :: string?

时间:2011-02-22 09:43:32

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

是否可以格式化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);

3 个答案:

答案 0 :(得分:12)

最多C ++ - 实现类似sprintf功能的方法是使用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所指出的,这种做法不允许使用可变参数,因为事先没有构建“模板”字符串,允许流迭代向量并根据占位符插入数据。

答案 1 :(得分:9)

您可以使用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';
}

你可以在这里工作,模仿等等。

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

答案 2 :(得分:1)

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

至于将普通向量作为输入,如果tokens.size()<2,你想要发生什么?难道你不必确保向量足够大以在任何情况下索引元素0和1吗?