Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Boost spirit x3: Parse vector, but only conditionally take items into result

Consider strings of the form (int ":" int )*. I want to parse such a string into a vector of integers, in the following way: if the second value is odd, add the first to the result. Otherwise, do nothing for this pair.

I am trying around with

  auto pair_ = x3::rule<class pair_, int>() 
             = x3::int_ >> ":" >> x3::int_;
  auto vec   = x3::rule<class vec, std::vector<int>>() 
             = (*pair_[
                 ([](auto &c){
                     if(x3::_attr(c).second % 2) 
                         x3::_val(c).push_back(x3::_attr(c).first);
                 })
               ]);

which seems to be wrong.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Additional task: make : int optional, and default to 1. I tried

  auto pair_ = x3::rule<class pair_, int>() 
             = x3::int_ >> ((":" >> x3::int_) | x3::attr(1));

Example: 10 11:0 12:3 should become the vector [10, 12].

which also seems to be wrong.

How do I do it correctly?

>Solution :

Your pair_ rule exposes only an int. Changing

auto pair_ 
    = x3::rule<class pair_, std::pair<int, int> >() 
    = x3::int_ >> ":" >> x3::int_;

Will work, although you have to include

#include <boost/fusion/adapted/std_pair.hpp>

directly or indirectly. The optional version also just works:

auto pair_ 
    = x3::rule<class pair_, std::pair<int, int> >() 
    = x3::int_ >> (":" >> x3::int_ | x3::attr(1));

Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>
#include <fmt/ranges.h>
namespace x3 = boost::spirit::x3;

namespace Parsing {
    auto pair_ 
        = x3::rule<class pair_, std::pair<int, int> >() 
        = x3::int_ >> (":" >> x3::int_ | x3::attr(1));

    auto action = [](auto& ctx) {
        if (_attr(ctx).second % 2)
            _val(ctx).push_back(_attr(ctx).first);
    };
    auto vec 
        = x3::rule<class vec, std::vector<int>>() 
        = *pair_[action];
}

int main() {
    for (std::string_view input : {
            "",
            "12:4 1:1",
            "12:4 1:1 2:2 3:3 4:4 5:5",
            "12:4 1 2 3 4 5:5",
            }) {
        std::vector<int> v;
        if (bool ok = phrase_parse(begin(input), end(input), Parsing::vec, x3::space, v))
            fmt::print("{}\t'{}' -> {}\n", ok, input, v);
    }
}

Printing

true    '' -> []
true    '12:4 1:1' -> [1]
true    '12:4 1:1 2:2 3:3 4:4 5:5' -> [1, 3, 5]
true    '12:4 1 2 3 4 5:5' -> [1, 2, 3, 4, 5]
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading