Повысьте проблемы со шкипером

У меня проблемы с бодибилдером.

Мне нужно разобрать файл так:

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

Я могу разобрать его без проблем (благодаря stackoverflow;), только если я добавлю '_' после первого инт.

На самом деле, я думаю, что шкипер съедает конец строки после первого int, поэтому первая и вторая (на второй строке) выглядят как только одно int. Я нене понимаю, как сохранить eol, но есть места. Я'Мы нашли примеры использования пользовательского парсера, такого какВот а такжеВот.

Я пробовал qi :: blank, пользовательский парсер с одним освещенным правилом (' ') Независимо от того, каким шкипером я пользуюсь, космос и eol всегда есть.

Моя грамматика:

строка:

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

полная проблема хранится в структуре:

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

анализатор строк:

template
struct row_parser : qi::grammar
{
    row_parser() : row_parser::base_type(start)
    {

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

    qi::rule start;
    qi::rule list;
};

и анализатор проблем:

template
struct problem_parser : qi::grammar
{

    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 start;
    row_parser row;
};

И я использую это так:

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

Конечно, qi :: space - это моя проблема, и одним из способов решения этой проблемы было быя не использую шкипер, но длятекст_парсера требует его, а моему парсеру - один.

я застрял с некоторых часов ... я думаю, что этоЧто-то очевидное, что я неправильно понял.

Спасибо за вашу помощь.

Ответы на вопрос(1)

Решение Вопроса

в середине грамматики:

qi::lexeme [ p ]

который запрещает шкипера, например, если вы хотите быть уверены, что вы анализируете идентификатор без внутренних пропусков)

qi::raw [ p ]

который анализирует как всегда, включая пропуски, но возвращает необработанный диапазон итераторов соответствующей исходной последовательности (включая пропущенные позиции)

qi::no_skip [ p ]

Блокировка пропуска без предварительного пропускаqi::skip(s) [ p ]

который заменяет шкипера другим шкиперомs в целом (обратите внимание, что вам нужно использовать соответственно объявленныеqi::rule<> случаи внутри такогоskip[] оговорка)

гдеp это любое выражение парсера.

Конкретное решение

Ваша проблема, как вы уже знаете, может бытьqi::space съедаетвсе пробельные. Я могу'возможно, не знаю, что не так в вашей грамматике (так как вы неt показать либо полную грамматику, либо соответствующий ввод).

Поэтому здесьчто ябуду писать. Заметка

использование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";
}
</std::string::const_iterator></iterator,></iterator,></iterator,></iterator,problemtype(),qi::blank_type></typename></rowtype></unsigned></rowtype></unsigned></boost></boost></boost>

Если вы действительно нея не хочу разрывать строки:

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::string::const_iterator></iterator,></iterator,></iterator,></iterator,problemtype(),qi::space_type></typename>
Обновить

В ответ на комментарий: вот фрагмент, который показывает, как читать входные данные из файла. Это было проверено и отлично работает для меня:

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::istream_iterator>
 sehe13 июн. 2013 г., 13:43
Вы, вероятно, забыли установитьstd::ios::binary и / илиstd::noskipws в файловом потоке? Другое решение заключается в многопроходной адаптацииstd::istreambuf_iterator вместоstd::istream_iterator IIRC
 sehe13 июн. 2013 г., 13:49
Я обновил ответ, включив в него фрагмент, показывающий, как читать из файла ("input.txt") с тем же парсером. Смотрите наОбновить дно.
 audric13 июн. 2013 г., 13:36
Хорошо, спасибо (снова). Работает со строкой типа 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 "; но не, если я читаю это из файла с многопроходным парсером. Я нене понимаю почему. Любая идея ?
 audric13 июн. 2013 г., 13:57
Да, это работает! Спасибо !
 user2357307 мая 2015 г., 12:47
@sehe, спасибо за пример потока; первое, что сработало для меня.

Ваш ответ на вопрос