C++11 Эквивалент Boost.Format

Что-нибудь вроде Boost.Format в стандарте C++11? Мне удалось избежать использования Boost с лучшим вариантом C++11 для любых других нужд, которые у меня были.

В этом отношении Boost.Format не держит свечу к синтаксису Python format(), Нечто подобное было бы еще лучше.

5 ответов

Решение

Есть предложение для чего-то похожего на boost-формат. Тем не менее, он не является ни частью C++ 11, ни C++14, и ничего не имеет отношения к форматированию строк.

Здесь вы можете найти последнее предложение. В отличие от boost-формата, он основан на вариационных шаблонах.

Как правильно указывает nosid, ни C++11, ни C++14 не предоставляют эквивалента Boost Format.

However, the fmt library which optionally uses C++11 features such as variadic templates provides an implementation of the Python-like format функция:

std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");

and safe alternatives to *printf функции:

fmt::printf("The answer is %d\n", 42);

Disclaimer: I'm the author of this library

Реализация функции строкового формата в Python-формате с регулярным выражением C++11 и шаблонами с переменными числами.

/**
   Helper code to unpack variadic arguments
*/
namespace internal
{
    template<typename T>
    void unpack(std::vector<std::string> &vbuf, T t)
    {
        std::stringstream buf;
        buf << t;
        vbuf.push_back(buf.str());
    }
    template<typename T, typename ...Args>
    void unpack(std::vector<std::string> &vbuf, T t, Args &&... args)
    {
        std::stringstream buf;
        buf << t;
        vbuf.push_back(buf.str());
        unpack(vbuf, std::forward<Args>(args)...);
    }
}

/**
    Python-like string formatting
 */
template<typename ... Args>
std::string format(const std::string& fmt, Args ... args)
{
    std::vector<std::string> vbuf;  // store arguments as strings
    std::string in(fmt), out;    // unformatted and formatted strings
    std::regex re_arg("\\{\\b\\d+\\b\\}");  // search for {0}, {1}, ...
    std::regex re_idx("\\b\\d+\\b");        // search for 0, 1, ...
    std::smatch m_arg, m_idx;               // store matches
    size_t idx = 0;                         // index of argument inside {...}

    // Unpack arguments and store them in vbuf
    internal::unpack(vbuf, std::forward<Args>(args)...);

    // Replace all {x} with vbuf[x]
    while (std::regex_search(in, m_arg, re_arg)) {
        out += m_arg.prefix();
        if (std::regex_search(m_arg[0].str(), m_idx, re_idx)) {
            idx = std::stoi(m_idx[0].str());
        }
        if(idx < vbuf.size()) {
            out += std::regex_replace(m_arg[0].str(), re_arg, vbuf[idx]);
        }
        in = m_arg.suffix();
    }
    out += in;
    return out;
}

Пример: http://cpp.sh/6nli

      template<typename... Args>
std::string fmt_str(const std::string& fmt, Args... args)
{
    static const int bufferSize = 1000;
    char buffer[bufferSize];
    int n = snprintf(buffer, bufferSize, fmt.c_str(), args...);
    assert(n >= 0 and n <= bufferSize - 1 && "check fmt_str output");

    return (buffer);
}

//На основе Маркуса, небольшие улучшения: изменение ввода на ref, буфер избегает нового, использование snprintf во избежание переполнения буфера, прямой возврат во избежание конструктора копирования. Использование в моем проекте

// Это должен быть комментарий к Markus Dutschke, а не ответ, но поле комментария не может правильно отформатировать фрагмент кода, и я извлекаю код здесь.

используя sprintf

  • Для C++20 используйте std::format
  • есть fmt-библиотека с версии C++11 на
  • простое решение для форматированного вывода - printf
  • использовать синтаксис printf для написания std::stringиспользуйте следующий фрагмент

минимальный воспроизводимый пример: формат std::string с синтаксисом printf

интерактивная версия

#include <iostream>
#include <string>
#include <stdio.h>
#include <assert.h>


template<typename... Args>
std::string fmt_str(std::string fmt, Args... args)
{
    size_t bufferSize = 1000;
    char *buffer = new char[bufferSize];
    int n = sprintf(buffer, fmt.c_str(), args...);
    assert (n >= 0 and n < (int) bufferSize - 1  && "check fmt_str output");

    std::string fmtStr (buffer);
    delete buffer;
    return fmtStr;
}



int main()
{
    int a=1, b=2;
    double c=3.;
    std::cout << fmt_str("%d plus %d is %f", a, b, c) << std::endl;
    return 0;
}

вывод

1 plus 2 is 3.000000
Другие вопросы по тегам