Home > Mobile >  How can I use the C regex library to find a match and *then* replace it?
How can I use the C regex library to find a match and *then* replace it?

Time:11-14

I am writing what amounts to a tiny DSL in which each script is read from a single string, like this:

"func1;func2;func1;4*func3;func1"

I need to expand the loops, so that the expanded script is:

"func1;func2;func1;func3;func3;func3;func3;func1"

I have used the C standard regex library with the following regex to find those loops:

regex  REGEX_SIMPLE_LOOP(":?[0-9] )\\*([_a-zA-Z][_a-zA-Z0-9]*;");
smatch match;
bool   found = std::regex_search(*this, match, std::regex(REGEX_SIMPLE_LOOP));

Now, it's not too difficult to read out the loop multiplier and print the function N times, but how do I then replace the original match with this string? I want to do this:

if (found) match[0].replace(new_string);

But I don't see that the library can do this.

My backup place is to regex_search, then construct the new string, and then use regex_replace, but it seems clunky and inefficient and not nice to essentially do two full searches like that. Is there a cleaner way?

CodePudding user response:

You can also NOT use regex, the parsing isn't too difficult. So regex might be overkill. Demo here : https://onlinegdb.com/RXLqLtrUQ- (and yes my output gives an extra ; at the end)

#include <string>
#include <sstream>
#include <iostream>

int main()
{
    std::istringstream is{ "func1;func2;func1;4*func3;func1" };
    std::string split;

    // use getline to split
    while (std::getline(is, split, ';'))
    {
        // assume 1 repeat
        std::size_t count = 1;

        // if split part starts with a digit 
        if (std::isdigit(split.front()))
        {
            // look for a *
            auto pos = split.find('*');
            
            // the first part of the string contains the repeat count
            auto count_str = split.substr(0, pos);

            // convert that to a value
            count = std::stoi(count_str);

            // and keep the rest ("funcn")
            split = split.substr(pos   1, split.size() - pos - 1);
        }

        // now use the repeat count to build the output string
        for (std::size_t n = 0; n < count;   n)
        {
            std::cout << split << ";";
        }
    }

    // TODO invalid input string handling.

    return 0;
}
  • Related