Reputation: 161
I have some complicated structures and i want to extract their data from a text using boost::spirit library (I've selected this one for efficiency purpose).
but i will ask my question in simpler way.
assume, we have two structures like these:
struct person
{
std::string name;
uint8_t age;
};
and
struct fruit
{
std::string color;
std::double average_weight;
};
and our text that included these data is presented below:
"... (jane, 23) (david, 19) (mary, 30) [yello,100] [green, 60.6] [red, 30.5]"
now, the problem is "extracting these data in suitable format"
for example by call handler for each struct or push_back them on vector.
any help would be greatly appreciated!
is there any code sample about that?!
Upvotes: 2
Views: 273
Reputation: 1645
call handlers for parsed structures.
#include <string>
#define BOOST_RESULT_OF_USE_DECLTYPE
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;
struct person
{
std::string name;
uint8_t age;
};
BOOST_FUSION_ADAPT_STRUCT
(
person,
(std::string, name)
(uint8_t, age)
);
struct fruit
{
std::string color;
double average_weight;
};
BOOST_FUSION_ADAPT_STRUCT
(
fruit,
(std::string, color)
(double, average_weight)
);
template <typename _Iterator>
struct parser :
qi::grammar<_Iterator, void(), ascii::space_type>
{
parser() :
parser::base_type(main)
{
main =
*(
_person[ ([](const person &person_)
{
// Add handler here
}) ]
| _fruit[ ([](const fruit &fruit_)
{
// Add handler here
}) ]
);
_person = qi::lit('(') >> *(qi::char_ - ',') >> ',' >> qi::ushort_ >> ')';
_fruit = qi::lit('[') >> *(qi::char_ - ',') >> ',' >> qi::double_ >> ']';
}
qi::rule<_Iterator, void(), ascii::space_type> main;
qi::rule<_Iterator, person(), ascii::space_type> _person;
qi::rule<_Iterator, fruit(), ascii::space_type> _fruit;
};
int main()
{
typedef std::string::const_iterator iterator;
std::string input_ = "(jane, 23000) (david, 19) (mary, 30) [yello,100] [green, 60.6] [red, 30.5]";
iterator iterator_ = std::begin(input_);
bool result_ = qi::phrase_parse(iterator_, iterator(std::end(input_)), parser<iterator>(), ascii::space)
&& iterator_ == std::end(input_);
return 0;
}
P.S. Not all compiler can build that code because of lambdas in semantic actions. (msvs don't) In this case you have to use something else (phoenix::bind for example)
store parsed structures in a vector
typedef boost::variant <
person,
fruit
> variant;
template <typename _Iterator>
struct parser :
qi::grammar<_Iterator, std::vector < variant > (), ascii::space_type>
{
parser() :
parser::base_type(main)
{
main = *(_person | _fruit);
_person = qi::lit('(') >> *(qi::char_ - ',') >> ',' >> qi::ushort_ >> ')';
_fruit = qi::lit('[') >> *(qi::char_ - ',') >> ',' >> qi::double_ >> ']';
}
qi::rule<_Iterator, std::vector < variant > (), ascii::space_type> main;
qi::rule<_Iterator, person(), ascii::space_type> _person;
qi::rule<_Iterator, fruit(), ascii::space_type> _fruit;
};
Upvotes: 1