Использование Boost Spirit для разбора текстового файла с пропуском больших его частей

У меня есть следующее std::string:

<lots of text not including "label A" or "label B">    
label A: 34
<lots of text not including "label A" or "label B">
label B: 45
<lots of text not including "label A" or "label B">
...

Я хочу извлечь одиночные целые числа после всех вхождений label A или label B и поместить их в соответствующие vector<int> a, b. Простой, но не элегантный способ сделать это — использовать find("label A") и find("label B") и анализировать то, что будет первым. Есть ли краткий способ выразить это с помощью Духа? Как пропустить все, кроме label A или label B?


person Paul Jurczak    schedule 26.03.2014    source источник


Ответы (1)


Вы можете просто

omit [ eol >> *char_ - ("\nlabel A:") ] >> eol

Пример: Жить на Coliru

В репозитории также есть директива seek[]. Следующее эквивалентно предыдущему:

 repo::seek [ eol >> &lit("int main") ] 

Вот пример, который анализирует исходный образец:

*repo::seek [ eol >> "label" >> char_("A-Z") >> ':' >> int_ ],

Это будет разобрано на std::vector<std::pair<char, int> > без всего остального.

На Coliru тоже:

#if 0
<lots of text not including "label A" or "label B">    
label A: 34
<lots of text not including "label A" or "label B">
label B: 45
<lots of text not including "label A" or "label B">
...
#endif
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
#include <fstream>

namespace qi   = boost::spirit::qi;
namespace repo = boost::spirit::repository::qi;

int main()
{
    std::ifstream ifs("main.cpp");
    ifs >> std::noskipws;

    boost::spirit::istream_iterator f(ifs), l;

    std::vector<std::pair<char, int> > parsed;
    using namespace qi;
    bool ok = phrase_parse(
            f, l, 
            *repo::seek [ eol >> "label" >> char_("A-Z") >> ':' >> int_ ],
            blank,
            parsed
        );

    if (ok)
    {
        std::cout << "Found:\n";
        for (auto& p : parsed)
            std::cout << "'" << p.first << "' has value " << p.second << "\n";
    }
    else
        std::cout << "Fail at: '" << std::string(f,l) << "'\n";
}

Примечания:

Выход

Found:
'A' has value 34
'B' has value 45
person sehe    schedule 26.03.2014
comment
Я отредактировал, чтобы показать директиву seek на ваших фактических демонстрационных данных. - person sehe; 26.03.2014