Изменение значения атрибута при разборе с помощью Boost Spirit - PullRequest
0 голосов
/ 26 февраля 2019

Учитывая строку «1, 2, 3, 10, 15», ожидаемый результат должен быть 01, 02, 03, 10, 15 - то есть добавление «0» к анализируемому атрибуту, если его размер не равен 2.Я бы легко сделал это с лямбдами как семантическими действиями, но как выполнить задачу, не используя их?Я подозреваю, что здесь нужно сыграть в некоторые хитрые игры qi :: _ val и qi :: _ 1.То, что я действительно хотел, было бы

s = qi::repeat(1,2)[qi::digit] 
[(
        [](auto& parsed_number)
        { 
            return parsed_number.size()==2 ? 
            parsed_number : std::string("0") + parsed_number;
        } 
 ]); 

, но это не работает таким образом

#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;

using V = std::vector<std::string>;

template<typename It, typename Skipper>
struct G: qi::grammar<It, V(), Skipper>
{
    G(): G::base_type(v)
    {
        v = s % ',';
        s = qi::repeat(1,2)[qi::digit];
    }
private:
    qi::rule<It, V(), Skipper> v;
    qi::rule<It, std::string(), Skipper> s;
};


int main()
{
    const std::string s = "1, 2, 3, 10, 15";
    std::string::const_iterator beg(s.begin()), e;
    G<decltype(beg), qi::space_type> g;
    V R;
    bool b = qi::phrase_parse(beg, e, g, qi::space, R);
    if(!b){
        std::cerr << "parsing failed\n";
        return -1;
    }

    for(const auto& r: R) std::cout << r << '\n';
}

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/at.hpp>
#include <vector>
#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace fusion= boost::fusion;

using V = std::vector<std::string>;

template<typename It, typename Skipper>
struct G: qi::grammar<It, V(), Skipper>
{
    G(): G::base_type(v)
    {
        v = s % ',';
        //s = qi::hold[qi::repeat(2)[qi::digit]]|(qi::attr('0') >> qi::digit);
        //s = (&qi::repeat(2)[qi::digit] | qi::attr('0')) >> qi::repeat(1,2)[qi::digit];
        //s = qi::as_string[qi::repeat(1,2)[qi::digit]] [qi::_val = phx::if_else(phx::size(qi::_1)==2,qi::_1,phx::val('0')+qi::_1)]; 
        s = qi::as_string[qi::repeat(1,2)[qi::digit]]
[(
        [](auto& parsed_number, auto& ctx)
        { 
            fusion::at_c<0>(ctx.attributes) = parsed_number.size()==2 ? 
            parsed_number : '0' + parsed_number;
        } 
 )]; 
    }
private:
    qi::rule<It, V(), Skipper> v;
    qi::rule<It, std::string(), Skipper> s;
};


int main()
{
    const std::string s = "1, 2, 3, 10, 15";
    std::string::const_iterator beg(s.begin()), e;
    G<decltype(beg), qi::space_type> g;
    V R;
    bool b = qi::phrase_parse(beg, e, g, qi::space, R);
    if(!b){
        std::cerr << "parsing failed\n";
        return -1;
    }

    for(const auto& r: R) std::cout << r << '\n';
}
0 голосов
/ 26 февраля 2019

Это то, что вы хотите?

#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <boost/spirit/include/karma.hpp>
#include <iterator>

namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;

using SNT = long int;
using V = std::vector<SNT>;

template<typename It, typename Skipper>
struct G: qi::grammar<It, V(), Skipper>
{
    G(): G::base_type(v)
    {
        v = s % ',';
        s = qi::int_parser<SNT>(); /*Change to  qi::int_parser<SNT,10,2> if you also only
 * want to accept at least 2 digit decimals*/
    }
private:
    qi::rule<It, V(), Skipper> v;
    qi::rule<It, SNT(), Skipper> s;
};

template<typename OutputIterator>
struct GG : karma::grammar<OutputIterator, V()> {
    GG() : GG::base_type(start) {
        start = karma::right_align(2,'0')[karma::int_generator<SNT>()] % '\n';

    }
    karma::rule<OutputIterator, V()> start;
};


int main()
{
    const std::string s = "1, 2, 3, 10, 15";
    std::string::const_iterator beg(s.begin()), e;
    G<decltype(beg), qi::space_type> g;
    V R;
    bool b = qi::phrase_parse(beg, e, g, qi::space, R);
    if(!b){
        std::cerr << "parsing failed\n";
        return EXIT_FAILURE;
    }

    for(const auto& r: R) std::cout << r << '\n';

    std::string o{};
    V O;
    GG<std::back_insert_iterator<std::string>> gg;
    b = karma::generate(std::back_inserter(o), gg, R);
    if (!b)
        throw std::runtime_error{"Generation failed"};

    std::cout << o;
}
...