Использование 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?

3

Решение

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

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

Пример: Жить на Колиру

Там также seek[] директива в хранилище. Следующее эквивалентно вышеуказанному:

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

Вот пример, который анализирует ваш оригинальный образец:

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

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

На колиру тоже:

#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";
}

Заметки:

  • seek действительно выставляет атрибут matched, который довольно мощный:

    repo::seek [ eol >> "label" >> char_("ABCD") >> ':' ]
    

    «съест» этикетку, но выставит письмо с этикеткой ('A', 'B', 'C', или же 'D') в качестве атрибута.

  • Производительность при пропуске может быть довольно удивительной, прочитайте предупреждение в документации http://www.boost.org/doc/libs/1_55_0/libs/spirit/repository/doc/html/spirit_repository/qi_components/directives/seek.html

Выход

Found:
'A' has value 34
'B' has value 45
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]