Я использую 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';
}
}