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.
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?
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));
#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]