素槿
Published on 2025-08-26 / 2 Visits
0

一种类似std::format的简单实现

std::string format(std::string_view fmt, Args&&... args)
{
    std::vector<std::string> fmt_args = build_args(args...);
    return format_helper(fmt, fmt_args);
}

constexpr std::vector<std::string> build_args(const auto&... args)
{
    std::vector<std::string> av{};
    std::ostringstream       oss;
    av.reserve(sizeof...(args));

    auto _build_args = [](const auto&                arg,
                            std::vector<std::string>& av) {
        std::ostringstream oss;
        oss << arg;
        av.emplace_back(oss.str());
    };

    [&]<size_t... I>(std::index_sequence<I...>) {
        ((_build_args(args, av)), ...);
    }(std::make_index_sequence<sizeof...(args)>());
    return av;
}

constexpr static ssize_t from_string(const std::string_view str)
{
    size_t  start = str.find_first_not_of(' ');
    size_t  end   = str.find_last_not_of(' ') + 1;
    ssize_t r     = 0;
    size_t  y     = end - start - 1;
    bool    once  = true;
    if(start >= end)
        return -1;

    for(size_t i = start; i < end; i++, y--) {
        if(!(str[i] >= '0' && str[i] <= '9'))
            throw std::invalid_argument(
                "The value must be a positive decimal integer");
        if(once && 0 == (str[i] - '0')) {
            once = false;
            continue;
        }
        r += (str[i] - '0') * ::powl(10, y);
    }

    return r;
}

std::string format_helper(
    std::string_view fmt, const std::vector<std::string>& fmt_args)
{
    size_t             index = 0;
    std::ostringstream oss;
    while(1) {
        size_t openbracket = fmt.find('{');
        if(openbracket == std::string_view::npos) {
            oss << fmt;
            return oss.str();
        }
        size_t closebracket = fmt.find("}", openbracket + 1);
        if(closebracket == std::string_view::npos) {
            oss << fmt;
            return oss.str();
        }
        ssize_t args_index = from_string(
            fmt.substr(openbracket + 1, closebracket - openbracket - 1));
        if(args_index == -1)
            args_index = index;

        oss << fmt.substr(0, openbracket);
        oss << fmt_args.at(args_index);
        fmt = fmt.substr(closebracket + 1);
        index++;
    }
    return oss.str();
}