具有空行和属性的基于行的解析器,如何忽略属性

时间:2018-10-22 06:12:31

标签: boost boost-spirit

我正在使用增强精神来分析基于行的格式,其中允许空行。为此,我使用类似于以下语法的内容:

struct parser_type : public qi::grammar<std::string::iterator, qi::ascii::blank_type, std::vector<int>()>
{
    typedef std::string::iterator Iterator;

    parser_type() : parser_type::base_type(main)
    {
        element = qi::int_;
        line %= element | qi::eps;
        main %= +(line >> qi::eol);
    }

    qi::rule<Iterator, int()> element;
    qi::rule<Iterator, qi::ascii::blank_type, int()> line;
    qi::rule<Iterator, qi::ascii::blank_type, std::vector<int>()> main;
} parser;

这很好,因为qi::epsqi::eol一起匹配空行。很好(尽管我愿意接受其他可能更好的方法来解析带空行的基于行的格式)。但是,line解析器的属性是int,显然它不存在于空行中。因此,对于

的输入
1


4

解析器创建一个向量,内容为{ 1, 0, 0, 4 }

我希望该行被完全忽略,也就是说,我不希望构造任何虚拟对象来匹配该行的属性。能做到吗?有没有更好的解析行的方法?

这是一个完整的最小示例(程序需要一个名为“ input”的输入文件,您可以使用上面的示例):

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

struct parser_type : public qi::grammar<std::string::iterator, qi::ascii::blank_type, std::vector<int>()>
{
    typedef std::string::iterator Iterator;

    parser_type() : parser_type::base_type(main)
    {
        element = qi::int_;
        line = element | qi::eps;
        main %= +(line >> qi::eol);
    }

    qi::rule<Iterator, int()> element;
    qi::rule<Iterator, qi::ascii::blank_type, int()> line;
    qi::rule<Iterator, qi::ascii::blank_type, std::vector<int>()> main;
} parser;

int main()
{
    std::ifstream file("input");
    std::stringstream buffer;
    buffer << file.rdbuf();

    std::string str = buffer.str();
    auto iter = str.begin();
    std::vector<int> lines;
    bool r = qi::phrase_parse(iter, str.end(), parser, qi::ascii::blank, lines);

    if (r && iter == str.end())
    {
        std::cout << "parse succeeded\n";
        for(auto e : lines)
        {
            std::cout << e << '\n';
        }
    }
    else
    {
        std::cout << "parse failed. Remaining unparsed: " << std::string(iter, str.end()) << '\n';
    }
}

1 个答案:

答案 0 :(得分:1)

此规则:

    line = element | eps;

使您失去所需的信息。通过接受不匹配(eps),您可以强制它只返回声明的值初始化属性(rul签名中的int)。

因此,删除它,然后我通常使用列表运算符(%)进行这种重复:

    line = element;
    main = -line % qi::eol;

这有效:

Live On Coliru

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/spirit/include/qi.hpp>    
namespace qi = boost::spirit::qi;

struct parser_type : public qi::grammar<std::string::iterator, qi::ascii::blank_type, std::vector<int>()>
{
    typedef std::string::iterator Iterator;

    parser_type() : parser_type::base_type(main)
    {
        element = qi::int_;
        line = element;
        main = -line % qi::eol;
    }

    qi::rule<Iterator, int()> element;
    qi::rule<Iterator, qi::ascii::blank_type, int()> line;
    qi::rule<Iterator, qi::ascii::blank_type, std::vector<int>()> main;
} parser;

int main()
{
    std::ifstream file("input");
    std::stringstream buffer;
    buffer << file.rdbuf();

    std::string str = buffer.str();
    auto iter = str.begin();
    std::vector<int> lines;
    bool r = qi::phrase_parse(iter, str.end(), parser, qi::ascii::blank, lines);

    if (r && iter == str.end())
    {
        std::cout << "parse succeeded\n";
        for(auto e : lines)
        {
            std::cout << e << '\n';
        }
    }
    else
    {
        std::cout << "parse failed. Remaining unparsed: " << std::string(iter, str.end()) << '\n';
    }
}

打印

parse succeeded
1
4