c++ - आत्मा कप्तान के मुद्दों को बढ़ावा देना



boost boost-spirit (1)

मुझे प्रोत्साहन भावना के साथ skippers परेशानी है

मुझे उस फ़ाइल को पार्स करने की आवश्यकता है:

ROW int
int [int, int]
int [int, int]
...

मैं बिना किसी समस्या के पार्स करने में सक्षम हूं (स्टैकरवर्फफ्लो के लिए धन्यवाद;) केवल अगर मैं पहली int के बाद एक '_' जोड़ता हूं

वास्तव में, मुझे लगता है कि कप्तान पहले इंट के बाद लाइन का अंत खा लेता है, इसलिए पहला और दूसरा (दूसरी पंक्ति पर) केवल एक int के रूप में दिखता है मुझे नहीं पता कि ईओल कैसे रखना है, लेकिन रिक्त स्थान खाने के लिए। मैंने यहां और यहां की तरह कस्टम पार्सर का उपयोग करने के लिए उदाहरण पाये हैं

मैंने क्यूई :: रिक्त, कस्टम पार्सर की कोशिश की, एक सिंगल नियम के साथ रोशनी ('') कोई फर्क नहीं पड़ता कि कप्तान जो मैं करता हूं, स्थान और ईओएल हमेशा खाती है

मेरा व्याकरण है:

एक पंक्ति:

struct rowType
{
    unsigned int number;
    std::list<unsigned int> list;
};

पूरी संरचना एक संरचना में संग्रहीत है:

struct problemType
{
    unsigned int ROW;
    std::vector<rowType> rows;
};

पंक्ति पार्सर:

template<typename Iterator>
struct row_parser : qi::grammar<Iterator, rowType(), qi::space_type>
{
    row_parser() : row_parser::base_type(start)
    {

        list  = '[' >> -(qi::int_ % ',') >> ']';
        start = qi::int_ >> list;
    }

    qi::rule<Iterator, rowType(), qi::space_type> start;
    qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list;
};

और समस्या पार्सर:

template<typename Iterator>
struct problem_parser : qi::grammar<Iterator,problemType(),qi::space_type>
{

    problem_parser() : problem_parser::base_type(start)
    {
        using boost::phoenix::bind;
        using qi::lit;

        start = qi::int_ >> lit('_') >> +(row);

        //BOOST_SPIRIT_DEBUG_NODE(start);
    }

    qi::rule<Iterator, problemType(),qi::space_type> start;
    row_parser<Iterator> row;
};

और मैं इसे इस तरह प्रयोग करता हूं:

main() {
static const problem_parser<spirit::multi_pass<base_iterator_type> > p;
...
spirit::qi::phrase_parse(first, last ,
            p,
            qi::space,
            pb);
}

बेशक, क्यूई :: स्पेस मेरी समस्या है, और मेरी समस्या को सुलझाने का एक तरीका एक कप्तान का उपयोग नहीं करना होगा, लेकिन वाक्यांश के लिए एक की आवश्यकता है, और उसके बाद मेरे पार्सर को एक की आवश्यकता है।

अब कुछ घंटों से मैं फंस गया हूं ... मुझे लगता है कि यह कुछ स्पष्ट है, मैंने गलत समझा है।

आपकी सहायता के लिए धन्यवाद.


सामान्यतया निम्नलिखित निदेशकों के मध्य-व्याकरण में बाधा आना / स्विचिंग करने के लिए सहायक होते हैं:

  • qi::lexeme [ p ]
    जो एक कप्तान को रोकता है, उदाहरण के लिए यदि आप यह सुनिश्चित करना चाहते हैं कि आप किसी आंतरिक पहचान के बिना एक पहचानकर्ता को पार्स करते हैं)

  • qi::raw [ p ]
    जो हमेशा की तरह पार्स करता है, जिसमें रुक जाती है, लेकिन मिलान किए गए स्रोत अनुक्रम (छोड़े गए पदों सहित) की कच्ची आवर्ती रेंज देता है

  • qi::no_skip [ p ]
    पूर्व-छोड़ा बिना बाधा को रोकना
  • qi::skip(s) [ p ]
    जो कि कप्तान को दूसरे कप्तान की जगह लेता है (ध्यान दें कि इस तरह के एक skip[] खंड में उचित घोषित qi::rule<> उदाहरणों का उपयोग करना आवश्यक है)

जहां p कोई पार्सर अभिव्यक्ति है

विशिष्ट समाधान

आपकी समस्या, जैसा कि आप पहले से ही जानते हैं, हो सकता है कि qi::space सभी रिक्त qi::space खाती है मुझे संभवतः पता नहीं है कि आपके व्याकरण में क्या गलत है (क्योंकि आप संपूर्ण व्याकरण या प्रासंगिक इनपुट नहीं दिखाते हैं)।

इसलिए, यहाँ मैं क्या लिखूँगा ध्यान दें

  • qi::eol का उपयोग विशिष्ट स्थानों पर स्पष्ट रूप से लाइन ब्रेक की आवश्यकता होती है
  • एक कप्तान के रूप में qi::blank का उपयोग ( eol भी शामिल नहीं)
  • संक्षेप के लिए मैंने व्याकरण को जोड़ दिया

कोड:

#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

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

struct rowType {
    unsigned int number;
    std::list<unsigned int> list;
};

struct problemType {
    unsigned int ROW;
    std::vector<rowType> rows;
};

BOOST_FUSION_ADAPT_STRUCT(rowType, (unsigned int, number)(std::list<unsigned int>, list))
BOOST_FUSION_ADAPT_STRUCT(problemType, (unsigned int, ROW)(std::vector<rowType>, rows))

template<typename Iterator>
struct problem_parser : qi::grammar<Iterator,problemType(),qi::blank_type>
{
    problem_parser() : problem_parser::base_type(problem)
    {
        using namespace qi;
        list    = '[' >> -(int_ % ',') >> ']';
        row     = int_ >> list >> eol;
        problem = "ROW" >> int_ >> eol >> +row;

        BOOST_SPIRIT_DEBUG_NODES((problem)(row)(list));
    }

    qi::rule<Iterator, problemType()            , qi::blank_type> problem;
    qi::rule<Iterator, rowType()                , qi::blank_type> row;
    qi::rule<Iterator, std::list<unsigned int>(), qi::blank_type> list;
};

int main()
{
    const std::string input = 
        "ROW 1\n"
        "2 [3, 4]\n"
        "5 [6, 7]\n";

    auto f = begin(input), l = end(input);

    problem_parser<std::string::const_iterator> p;
    problemType data;

    bool ok = qi::phrase_parse(f, l, p, qi::blank, data);

    if (ok) std::cout << "success\n";
    else    std::cout << "failed\n";

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

यदि आप वाकई लाइन ब्रेक की आवश्यकता नहीं चाहते हैं:

template<typename Iterator>
struct problem_parser : qi::grammar<Iterator,problemType(),qi::space_type>
{
    problem_parser() : problem_parser::base_type(problem)
    {
        using namespace qi;
        list    = '[' >> -(int_ % ',') >> ']';
        row     = int_ >> list;
        problem = "ROW" >> int_ >> +row;

        BOOST_SPIRIT_DEBUG_NODES((problem)(row)(list));
    }

    qi::rule<Iterator, problemType()            , qi::space_type> problem;
    qi::rule<Iterator, rowType()                , qi::space_type> row;
    qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list;
};

int main()
{
    const std::string input = 
        "ROW 1 " // NOTE whitespace, obviously required!
        "2 [3, 4]"
        "5 [6, 7]";

    auto f = begin(input), l = end(input);

    problem_parser<std::string::const_iterator> p;
    problemType data;

    bool ok = qi::phrase_parse(f, l, p, qi::space, data);

    if (ok) std::cout << "success\n";
    else    std::cout << "failed\n";

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

अद्यतन करें

टिप्पणी के जवाब में: यहां एक स्निपेट है जो दर्शाता है कि किसी फ़ाइल से इनपुट कैसे पढ़ा जाए। यह परीक्षण किया गया और मेरे लिए ठीक काम करता है:

std::ifstream ifs("input.txt"/*, std::ios::binary*/);
ifs.unsetf(std::ios::skipws);

boost::spirit::istream_iterator f(ifs), l;

problem_parser<boost::spirit::istream_iterator> p;




boost-spirit-qi