Анализатор на основе строк с пустыми строками и атрибутами, как игнорировать атрибут - PullRequest
0 голосов
/ 22 октября 2018

Я использую 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::eps вместе с qi::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 голосов
/ 22 октября 2018

Это правило:

    line = element | eps;

приводит к потере необходимой вам информации. принимая no-match (eps), вы заставляете его просто возвращать объявленный вами атрибут с инициализированным значением (int в подписи rul).

Итак, отбросьтеи затем я обычно пишу этот вид повтора, используя оператор списка (%):

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

Это работает:

LiveНа 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...