Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse a string into std::map and validate its format?

Tags:

c++

regex

parsing

I'd like to parse a string like "{{0, 1}, {2, 3}}" into a std::map. I can write a small function for parsing a string using <regex> library, but I have no idea how to check whether a given string is in a valid format. How can I validate the format of a string?

#include <list>
#include <map>
#include <regex>
#include <iostream>

void f(const std::string& s) {
  std::map<int, int> m;
  std::regex p {"[\\[\\{\\(](\\d+),\\s*(\\d+)[\\)\\}\\]]"};
  auto begin = std::sregex_iterator(s.begin(), s.end(), p);
  auto end = std::sregex_iterator();
  for (auto x = begin; x != end; ++x) {
    std::cout << x->str() << '\n';
    m[std::stoi(x->str(1))] = std::stoi(x->str(2));
  }
  std::cout << m.size() << '\n';
}

int main() {
  std::list<std::string> l {
    "{{0, 1},   (2,    3)}",
    "{{4,  5, {6, 7}}" // Ill-formed, so need to throw an excpetion.
  };
  for (auto x : l) {
    f(x);
  }
}

NOTE: I don't feel obliged to use regex to solve this problem. Any kind of solutions, including some ways validating and inserting at once by subtracting substrings, will be appreciated.

like image 622
Han Avatar asked Jun 17 '26 19:06

Han


1 Answers

In my opinion, Spirit-based parser is always much more robust and readable. It is also much more fun to parse with Spirit :-). So, in addition to @Aleph0 's answer, I'd like to provide a compact solution based on Spirit-X3:

#include <string>
#include <map>
#include <iostream>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>

int main() {
    std::string input ="{{0, 1},  {2, 3}}";
    using namespace boost::spirit::x3;
    const auto pair = '{' > int_ > ',' > int_ > '}';
    const auto pairs = '{' > (pair % ',')  > '}';
    std::map<int, int> output;
    // ignore spaces, tabs, newlines
    phrase_parse(input.begin(), input.end(), pairs, space, output);

    for (const auto [key, value] : output) {
        std::cout << key << ":" << value << std::endl;
    }
}

Note that I used operator >, which means "expect". So, if the input does not match the expectation, Spirit throws an exception. If you prefer a silent failure, use operator >> instead.

like image 63
Igor R. Avatar answered Jun 20 '26 08:06

Igor R.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!