我正在尝试使用boost.spirit库为csv文件编写解析器。我遇到以下编译错误。我是boost.spirit的新手,所以有人能找出原因吗?
错误消息是:
错误C2664:'bool boost :: spirit :: qi :: rule :: parse(Iterator&,const Iterator&,Context&,const Skipper&,Attribute&)const':无法转换参数1从'const char *'到'std :: _ String_iterator>> &安培;”
我的代码是:
#pragma once
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include<vector>
#include<string>
#include<memory>
#include<boost/iostreams/device/mapped_file.hpp> // for mmap
#include<boost/utility/string_ref.hpp>
#include<boost/spirit/include/qi.hpp>
#include<boost/spirit/include/qi_grammar.hpp>
#include<boost/spirit/include/qi_real.hpp>
#include<boost/spirit/include/phoenix.hpp>
#include<boost/spirit/include/qi_symbols.hpp>
typedef boost::string_ref CsvField;
typedef std::vector<CsvField> CsvLine;
typedef std::vector<CsvLine> CsvFile;
namespace qi = boost::spirit::qi;
template <typename T> struct CsvParser : qi::grammar<T, CsvFile()> {
CsvParser() : CsvParser::base_type(lines) {
using namespace qi;
using boost::phoenix::construct;
using boost::phoenix::size;
using boost::phoenix::begin;
using boost::spirit::qi::float_;
field = raw[*~char_(",\r\n")][_val = construct<CsvField>(begin(qi::_1), size(qi::_1))]; // semantic action
//field = qi::float_;
line = field % ',';
lines = line % eol;
}
// declare: line, field, fields
qi::rule<T, CsvFile()> lines;
qi::rule<T, CsvLine()> line;
qi::rule<T, CsvField()> field;
};
代码真的来自Complete Graphs,所以我没有任何线索。我正在使用Microsoft Visual Studio 2015并提升1.16.0。
如果我将typedef boost::string_ref CsvField
替换为typedef std::string
,或者将字段的解析器替换为field = *(~char_(",\r\n"))
,则会出现同样的错误。
此外,我正在解析的文件实际上是一个标准的csv文件,因此欢迎任何替代解析方法的建议。唯一的问题是该文件有数百万行,因此标准的逐行解析对我来说不起作用。
答案 0 :(得分:0)
您没有显示相关代码。您所拥有的只是一个模板类,但是任何实例化是否格式正确取决于您实例化它。
现在我假设您正在尝试使用std::string::const_iterator
作为迭代器类型进行实例化 - 这有点像w.r.t.提到内存映射和string_ref(这意味着你希望做一切零拷贝)。
然而,问题是raw[]
公开了源迭代器类型的iterator_range,这意味着你传递std::string::const_iterator
作为string_ref
的第一个参数(别名CsvField
})构造函数。那不会起作用。
修复:
field = raw[*~char_(",\r\n")][_val = construct<CsvField>(&*begin(qi::_1), size(qi::_1))]; // semantic action
要真的好,你应该将std::addressof
包裹在一个凤凰演员中并使用它代替operator&
。我将此作为练习留给读者。
<强> Live On Coliru 强>
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include<boost/utility/string_ref.hpp>
#include<boost/spirit/include/qi.hpp>
#include<boost/spirit/include/phoenix.hpp>
typedef boost::string_ref CsvField;
typedef std::vector<CsvField> CsvLine;
typedef std::vector<CsvLine> CsvFile;
namespace qi = boost::spirit::qi;
template <typename T> struct CsvParser : qi::grammar<T, CsvFile()> {
CsvParser() : CsvParser::base_type(lines) {
using namespace qi;
using boost::phoenix::construct;
using boost::phoenix::size;
using boost::phoenix::begin;
using boost::spirit::qi::float_;
field = raw[*~char_(",\r\n")][_val = construct<CsvField>(&*begin(qi::_1), size(qi::_1))]; // semantic action
//field = qi::float_;
line = field % ',';
lines = line % eol;
}
// declare: line, field, fields
qi::rule<T, CsvFile()> lines;
qi::rule<T, CsvLine()> line;
qi::rule<T, CsvField()> field;
};
int main()
{
using It = std::string::const_iterator;
CsvParser<It> p;
std::string const input = R"([section1]
key1=value1
key2=value2
[section2]
key3=value3
key4=value4
)";
CsvFile parsed;
auto f = input.begin(), l = input.end();
bool ok = parse(f, l, p, parsed);
if (ok) {
std::cout << "Parsed: " << parsed.size() << " stuffs\n";
} else {
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining input: '" << std::string(f, l) << "'\n";
}
印刷:
Parsed: 7 stuffs