Я хочу ввести файл csv значительного размера, чтобы проанализировать его с помощью духа qi (с использованием boost 1.59.0). Есть примеры этого, и это выглядит прямо, но очевидная настройка на это приводит к ошибке компиляции, когда первый параметр qi :: phrase_parse (...) не принимается. Что здесь работает? (один пример по адресу: How to pass the iterator to a function in spirit qi ) Код:В духе форсирования используйте multi_pass с потоковым файловым входом, который нужен итератору
#define BOOST_SPIRIT_DEBUG
//#define BOOST_SPIRIT_DEBUG_PRINT_SOME 200
//#define BOOST_SPIRIT_DEBUG_OUT std::cerr
#include <stdio.h>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <fstream>
std::string dataLoc = "afile.csv";
namespace qi = boost::spirit::qi;
using Column = std::string;
using Columns = std::vector<Column>;
using CsvLine = Columns;
using CsvParsed = std::vector<CsvLine>;
template <typename It>
struct CsvGrammar : qi::grammar<It, CsvParsed(), qi::blank_type>
{
CsvGrammar() : CsvGrammar::base_type(start)
{
using namespace qi;
static const char colsep = '|';
start = -line % eol;
line = column % colsep;
column = quoted | *~char_(colsep);
quoted = '"' >> *("\"\"" | ~char_('"')) >> '"';
BOOST_SPIRIT_DEBUG_NODES((start)(line)(column)(quoted));
}
private:
qi::rule<It, CsvParsed(), qi::blank_type> start;
qi::rule<It, CsvLine(), qi::blank_type> line;
qi::rule<It, Column(), qi::blank_type> column;
qi::rule<It, std::string()> quoted;
};
int main()
{
std::ifstream inFile(dataLoc, std::ifstream::in);
if (inFile.good()) {
std::cout << "input found" << std::endl;
}
/*
// use either this block of code
typedef boost::spirit::istream_iterator istreamIter;
istreamIter fwd_begin = istreamIter(inFile);
istreamIter fwd_end = istreamIter();
*/
// or this block
typedef std::istreambuf_iterator<char> base_iterator_type;
typedef boost::spirit::multi_pass<base_iterator_type> forward_iterator_type;
base_iterator_type in_begin(inFile);
base_iterator_type in_end;
forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin);
forward_iterator_type fwd_end = boost::spirit::make_default_multi_pass(in_end);
CsvGrammar<std::string::const_iterator> p;
CsvParsed parsed;
bool ok = qi::phrase_parse(fwd_begin, fwd_end, p, qi::blank, parsed);
if (ok)
{
for(auto& line : parsed) {
for(auto& col : line)
std::cout << '[' << col << ']';
std::cout << std::endl;
}
} else
{
std::cout << "Parse failed\n";
}
if (fwd_begin != fwd_end)
std::cout << "Remaining unparsed: '" << std::string(fwd_begin, fwd_end) << "'\n";
}
Компилятор (Apple лязг 6.1 через CLion) дает следующее сообщение об ошибке:
In file included from /Users/alan/ClionProjects/csvreader/csvReader.cpp:16: In file included from /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/include/qi.hpp:16: In file included from /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi.hpp:21: In file included from /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/nonterminal.hpp:14: In file included from /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/nonterminal/rule.hpp:35: /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/reference.hpp:43:30: error: no matching member function for call to 'parse' return ref.get().parse(first, last, context, skipper, attr_); ~~~~~~~~~~^~~~~ /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/parse.hpp:164:40: note: in instantiation of function template specialization 'boost::spirit::qi::reference, std::__1::vector, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > >(), boost::proto::exprns_::expr >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> >::parse >, boost::spirit::iterator_policies::default_policy >, boost::spirit::context, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > > &, boost::fusion::nil_>, boost::spirit::locals >, boost::spirit::qi::char_class >, std::__1::vector, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > > >' requested here if (!compile(expr).parse( ^ /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/parse.hpp:197:20: note: in instantiation of function template specialization 'boost::spirit::qi::phrase_parse >, boost::spirit::iterator_policies::default_policy >, CsvGrammar >, boost::proto::exprns_::expr >, 0>, std::__1::vector, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > > >' requested here return qi::phrase_parse(first, last, expr, skipper, skip_flag::postskip, attr); ^ /Users/alan/ClionProjects/csvreader/csvReader.cpp:74:19: note: in instantiation of function template specialization 'boost::spirit::qi::phrase_parse >, boost::spirit::iterator_policies::default_policy >, CsvGrammar >, boost::proto::exprns_::expr >, 0>, std::__1::vector, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > > >' requested here bool ok = qi::phrase_parse(fwd_begin, fwd_end, p, qi::blank, parsed); ^ /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/nonterminal/rule.hpp:274:14: note: candidate function [with Context = boost::spirit::context, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > > &, boost::fusion::nil_>, boost::spirit::locals >, Skipper = boost::spirit::qi::char_class >, Attribute = std::__1::vector, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > > > >] not viable: no known conversion from 'boost::spirit::multi_pass >, boost::spirit::iterator_policies::default_policy >' to 'std::__1::__wrap_iter &' for 1st argument bool parse(Iterator& first, Iterator const& last ^ /Users/alan/ClionProjects/csvreader/boost/boost_1_59_0/boost/spirit/home/qi/nonterminal/rule.hpp:320:14: note: candidate function template not viable: requires 6 arguments, but 5 were provided bool parse(Iterator& first, Iterator const& last ^
Так выглядит как неправильный тип итератора подается в qi :: фраза_parse в качестве первого параметра. Что должно здесь идти?
Я думаю, что, возможно, вам не нужно вручную создать multi_pass итератор, и может просто передать IStream итератор? Попробуем ... –
@sehe nope not this time :) –
'std :: istream_iterator' никогда не принимается в выражениях парсера Spirit, насколько я знаю, но вижу мой ответ – sehe