raff
raff

Reputation: 359

Parse (replace) in C++ std::string

I have a "custom" string that has the following format. Example:

std::string MyString = "RndOrder%5d - RndCustomer%8s - RndHex%8x";

I would like to replace/parse the string:

Is there any function that helps me parse those "special marks"? Not sure if I would have to parse the string char by char and check for every possible combination.

Upvotes: 2

Views: 395

Answers (3)

Richard Hodges
Richard Hodges

Reputation: 69864

It's a candidate for std::snprintf (c++14), but take care to request the correct buffer size in one call, allocate a buffer and then format the string into the buffer:

#include <iostream>
#include <cstring>
#include <string>

template<class...Args>
std::string replace(const char* format, Args const&... args)
{
    // determine number of characters in output
    auto len = std::snprintf(nullptr, 0, format, args...);

    // allocate buffer space
    auto result = std::string(std::size_t(len), ' ');

    // write string into buffer. Note the +1 is allowing for the implicit trailing
    // zero in a std::string
    std::snprintf(&result[0], len + 1, format, args...);

    return result;
};

int main() {
    auto s = replace("RndOrder%5d - RndCustomer%8s - RndHex%8x", 5, "foo", 257);
    std::cout << s << std::endl;
}

expected output:

RndOrder    5 - RndCustomer     foo - RndHex     101

Upvotes: 1

Dusteh
Dusteh

Reputation: 1536

If the format can be variant (not always the fixed 3 arguments: %5d, %8s and %8x) and you want to be flexible in that manner, you should write your own implementation for that.

Assuming that count defined after % is a general digit (not only 5 or 8) you could try using the std::regex_search or std::regex_match to find the actual mnemonics you are looking for. For example your expression could look like %\d+[dsx]

Then you should parse it to find the COUNT and type and substitute with a random number acquired with the desired generator. To parse you could try updating the above expression to %(\d+)([dsx]) and capturing groups.

A sample parse implementation for your case could look like this:

std::string text = "RndOrder%5d - RndCustomer%8s - RndHex%8x";
auto reg = std::regex("%(\\d+)([sdx])");
std::smatch match;
while (std::regex_search(text, match, reg))
{
    const auto& full = match.str(); // in 1st iter contains "%5d"
    const auto& count = match.str(1); // in 1st iter contains "5"
    const auto& type = match.str(2); // in 1st iter contains "d"
    // further processing: type conversion, number generation, string replacement

    text = match.suffix().str();
}

For implementation example with search and group capturing you can also check out another question: Retrieving a regex search in C++

Upvotes: 2

Robin
Robin

Reputation: 1698

Ok, assuming that you're actually asking about string parsing here (and not random number/data generation)... have a look at this:

int iRandom1 = 12345;       // 5-digit decimal
int iRandom3 = 0x12345678;  // 8-digit hexadecimal
char cRandom2[9] = "RandomXY\0";  // Don't forget to NULL-terminate!
std::string sFormat = "RndOrder%5d - RndCustomer%8s - RndHex%8x";

char cResultBuffer[500];  // Make sure this buffer is big enough!

std::sprintf( cResultBuffer, sFormat.c_str(), iRandom1, cRandom2, iRandom3 );
std::string MyString = cResultBuffer;  // MyString = "RndOrder12345 - RndCustomerRandomXY - RndHex12345678";

Upvotes: 1

Related Questions