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

Line-based parser with empty lines and attributes, how to ignore attribute

我正在使用 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';
    }
}

这条规则:

    line = element | eps;

导致您丢失所需的信息。通过接受不匹配(eps),你强制它只return你声明的值初始化属性(int在rul签名).

所以,放弃它,然后我通常使用列表运算符 (%) 来写这种重复:

    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