Как я могу отформатировать std::string с помощью набора аргументов?
Можно ли форматировать 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
, которая берет набор аргументов и форматов a std::string/char *? Моя среда разработки - MS Visual С++ 2010 Express.
EDIT:
Я хотел бы добиться чего-то подобного:
sprintf_s(output, 1000, helloStringArr, tokens);
Ответы
Ответ 1
Вы можете сделать это с помощью библиотеки 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
Самый простой способ С++ для достижения функции sprintf-like - использовать 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
Edit
Как указано OP, этот способ делать вещи не допускает вариационных аргументов, потому что заранее не существует строковой строки, которая позволяет потоку перебирать вектор и вставлять данные в соответствии с заполнителями.
Ответ 3
Библиотека boost:: format может представлять интерес, если вы хотите избежать необходимости вручную обрабатывать выходной буфер.
Что касается принятия простого вектора в качестве ввода, что бы вы хотели, если tokens.size()<2
? Разве вы не должны были бы гарантировать, что вектор был достаточно большим, чтобы индексировать элементы 0 и 1 в любом случае?