【问题标题】:Boost spirit skipper issues提升精神船长问题
【发布时间】:2013-06-09 00:10:42
【问题描述】:

我在提升精神船长方面遇到了麻烦。

我需要解析这样的文件:

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

只有当我在第一个 int 之后添加一个“_”时,我才能毫无问题地解析它(感谢 stackoverflow;)。

事实上,我认为船长在第一个 int 之后吃掉了行尾,所以第一个和第二个(在第二行)看起来只有一个 int。我不明白如何保持 eol 但吃空间。我找到了使用自定义解析器的示例,例如 herehere

我尝试了 qi::blank,使用一条规则的自定义解析器 lit(' ') 无论我使用什么船长,空间和 eol 总是被吃掉。

我的语法是:

一行:

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::space 是我的问题,解决我的问题的一种方法是不使用船长,但phrase_parse 需要一个,然后我的解析器需要一个。

我已经被困了几个小时了...... 我认为这很明显是我误解了。

感谢您的帮助。

【问题讨论】:

    标签: c++ boost boost-spirit boost-spirit-qi


    【解决方案1】:

    一般来说,以下指令有助于在语法中禁止/切换跳过者:

    • qi::lexeme [ p ]
      禁止船长,例如如果您想确保解析没有内部跳过的标识符) - 另请参阅no_skip 进行比较

    • qi::raw [ p ]
      像往常一样解析,包括跳过,但返回匹配的源序列的原始迭代器范围(包括跳过的位置)

    • qi::no_skip [ p ]
      在没有 Pre-skip 的情况下禁止跳过(我创建了一个最小的示例来展示这里的区别:Boost Spirit lexeme vs no_skip

    • qi::skip(s) [ p ]
      将船长完全替换为另一个船长s(请注意,您需要在此类skip[] 子句中使用适当声明的qi::rule&lt;&gt; 实例)

    其中p 是任何解析器表达式。

    具体解决办法

    如您所知,您的问题可能是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";
    }
    

    更新

    作为对评论的回应:这里是一个 sn-p,它显示了如何从文件中读取输入。这已经过测试,对我来说效果很好:

    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;
    

    【讨论】:

    • 好的,谢谢(再次)。它适用于像 const std::string input = "ROW 7\n" "1 [1] [1,2]\n" "3 [1]\n" "4 [1, 3]\n" 这样的字符串"2 [1, 3]\n" "6 [2, 3] [4]\n" "5 [4, 6] [1]\n" "7 [1, 5] [2]\n";但如果我使用多通道解析器从文件中读取它,则不会。我不明白为什么。有什么想法吗?
    • 您可能忘记在文件流上设置std::ios::binary 和/或std::noskipws?另一种解决方案是多通道适应std::istreambuf_iterator&lt;&gt; 而不是std::istream_iterator&lt;&gt; IIRC
    • 我更新了答案以包含一个 sn-p,显示如何使用相同的解析器读取文件 ("input.txt")。请参阅底部的更新
    • @sehe,感谢流示例;第一个对我有用。
    猜你喜欢
    • 2014-03-07
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多