Как я могу отформатировать std :: string, используя набор аргументов? - PullRequest
15 голосов
/ 22 февраля 2011

Можно ли отформатировать 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.

EDIT: Я хотел бы добиться чего-то подобного:

sprintf_s(output, 1000, helloStringArr, tokens);

Ответы [ 3 ]

12 голосов
/ 22 февраля 2011

Самый лучший способ 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, такой способ действий не допускает использования переменных аргументов, поскольку заранее не построена строка `template ', позволяющая потоку выполнять итерации по вектору и вставлять данные в соответствии с заполнителями.

9 голосов
/ 22 февраля 2011

Вы можете сделать это с библиотекой 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';
}

Вы можете работать отсюда, создавать шаблоны и т. Д.

Обратите внимание, что он генерирует исключения (обратитесь к документации), если вектор не содержит точного количества аргументов. Вам нужно решить, как с ними справиться.

1 голос
/ 22 февраля 2011

Библиотека boost :: format может быть интересна, если вы хотите избежать ручной обработки выходного буфера.

Что касается принятия простого вектора в качестве входного, что будетты хочешь случиться если tokens.size()<2?Разве вы не должны убедиться, что вектор был достаточно большим, чтобы индексировать элементы 0 и 1 в любом случае?

...