Search code examples
c++string-formattingstdvectorstdstringfmt

How can I format a collection as a string efficiently in C++?


I have a program that has a string (which will need to be formatted) and takes a collection of elements from an external source.
The string must be formatted using the elements of the collection, which are std::string.
I can't formatting the string manually, such as:

// Just examples
sprintf(test, "%s this is my %s. This is a number: %d.", var[0], var[1], etc..);        // i can't do this
fmt::printf("%s this is my %s. This is a number: %d.", var[0], var[1], etc..);          // i can't do this (i also have fmt library)

This because the number of elements in the collection is variable.
What i would like to do is formatting the string as efficiently as possible.

This is the code:

std::string test = "%s this is my %s. This is a number: %d.";
std::vector<std::string> vec;

vec.push_back("Hello");
vec.push_back("string");
vec.push_back("5");


// String Formatting
std::size_t found;
for (auto i : vec)
{
    found = test.find("%");
    if (found != std::string::npos)
    {
        test.erase(found, 2);
        test.insert(found, i);
    }
}

std::cout << test;

Note1: I used a std::vector to manage the elements of the collection, but i could use any other structure.

That's why i didn't put the definitions in the code.

In addition, the code i wrote isn't work in case i have a string with a percentage, such as:

std::string test = "%s this is a percentage: %d%%. This is a number: %d.";
// Output = "Hello this is a percentage: string5. This is a number: %d."

In conclusion: What is the most efficient way to formatting the string with multiple elements?
Even without using a vector, but using another structure. Or using fmt or boost? (maybe boost decreases efficiency)
My development environment is Visual Studio 2019.


Solution

  • You can do this using fmt::dynamic_format_arg_store:

    #include <fmt/args.h>
    
    int main() {
      fmt::dynamic_format_arg_store<fmt::format_context> args;
      args.push_back("Hello");
      args.push_back("string");
      args.push_back("5");
      fmt::vprint("{} this is my {}. This is a number: {}.", args);
    }
    

    This prints (https://godbolt.org/z/jUbbUi):

    Hello this is my string. This is a number: 5.
    

    Note that {fmt} uses {} instead of % for replacement fields.