Как извлечь несколько структур из строки с помощью boost:: spirit


У меня есть несколько сложных структур, и я хочу извлечь их данные из текста с помощью boost:: spirit library (я выбрал эту библиотеку для повышения эффективности).

Но я задам свой вопрос более простым способом. Предположим, что у нас есть две структуры, подобные этим:
struct person 
{
   std::string name;
   uint8_t age; 
};

И

struct fruit
{
   std::string color;
   std::double average_weight;
};

И наш текст, который включал эти данные, представлен ниже:

"... (Джейн, 23) (Дэвид, 19) (Мэри, 30) [Йелло, 100] [зеленый, 60,6] [красный, 30,5] "

Итак, проблема в том, что "извлечение этих данных в соответствующем формате"

Например путем вызова обработчика для каждой структуры или push_back их по вектору.

Любая помощь будет очень признательна!

Есть ли какой-нибудь пример кода об этом?!

1 2

1 ответ:

Вызов обработчиков для проанализированных структур.

#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. Не все компиляторы могут построить такой код из-за лямбд в семантических действиях. (msvs не делают) в этом случае вы должны использовать что-то другое (phoenix::bind например)

Хранить разбираемые структуры в векторе

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;
};