0

I'm using a very nice and simple std::vector<std::string> initializer which takes an input string and regex. It's similar to a basic split, just it works with regex Group1 matches:

static std::vector<std::string> match(const std::string& str, const std::regex& re) {
    return { std::sregex_token_iterator(str.begin(), str.end(), re, 1), std::sregex_token_iterator() };
}

Construction of a vector is done like below:

std::string input = "aaa(item0,param0);bbb(item1,param1);cc(item2,param2);";
std::vector<std::string> myVector = match(input, std::regex(R"(\(([^,]*),)"));

This results a vector containing item0,item1,item2 extracted from an input string with regex:

enter image description here

Now my match function uses the first group results of the regex and (I believe) utilizes the vector's intialization form of:

std::vector<std::string> myVector = { ... };

I'd like to create a similar match function to construct a std::map<std::string,std::string>. Map also has the above initializator:

std::map<std::string,std::string> myMap = { {...}, {...} };

My idea is to modify the regex to create more group results:

enter image description here

And I would like to modify the above match function to create a nice map for me with the modified regex (\(([^,]*),([^)]*)), resulting the same as this:

std::map<std::string,std::string> myMap = { {"item0", "param0"}, {"item1", "param "}, {"item2", "param2"}, };

What I've tried?

static std::map<std::string, std::string> match(const std::string& str, const std::regex& re) {
    return { std::sregex_token_iterator(str.begin(), str.end(), re, {1,2}), std::sregex_token_iterator() };
}

This one (in case of a vector) would put both Group1 and Group2 results into the vector. But it can not initialize a map.

How can I still do that easily (Is it not possible with sregex_token_iterator)?

Daniel
  • 2,318
  • 2
  • 22
  • 53

1 Answers1

1

I don't know what 'easily' does mean exactly, so here comes simple solution:

#include <iostream>
#include <regex>
#include <vector>

static std::map<std::string, std::string> match(const std::string& str, const std::regex& re) {
    std::map<std::string, std::string> retVal;
    auto token = std::sregex_token_iterator(str.begin(), str.end(), re, {1,2});
    for (auto it=token++, jt=token; it != std::sregex_token_iterator(); ++it, jt = it++)
        retVal.emplace(*it,*jt);
    return retVal;
}

int main() {
    std::string input = "aaa(item0,param0);bbb(item1,param1);cc(item2,param2);";
    auto myVector = match(input, std::regex(R"(\(([^,]*),([^)]*))"));
    for (const auto& item : myVector)
        std::cout<<item.first<<'\t'<<item.second<<std::endl;
}

You can also could try to use boost and homemade generic algorithm.

Suthiro
  • 1,210
  • 1
  • 7
  • 18
  • Looks promising, is it possible somehow to skip the loop? – Daniel Apr 20 '21 at 07:52
  • I believe that loop cannot be skipped, only be hidden under the hood. Why do you want to hide the loop? – Suthiro Apr 20 '21 at 08:40
  • You're welcome! I just don't know how to deal with advancing the iterators by two steps each time using something like `std::transform`. I think it is possible, but I'm almost sure that the solution will not differ qualitatively from that provided in links above. – Suthiro Apr 20 '21 at 08:51