【发布时间】:2015-01-15 15:40:43
【问题描述】:
我正在尝试使用 boost spirit 解析一个 CSV 文件(带有标题行)。 csv 不是固定格式。有时有一些额外的列或列的顺序是混合的。我对几列感兴趣,它们的标题名称是众所周知的。
例如,我的 CSV 可能如下所示:
姓名、姓氏、年龄 约翰,能源部,32或者:
年龄、姓名 32,约翰我只想解析 Name 和 Age 的内容(注意,Age 是整数类型)。目前我提出了一个非常丑陋的解决方案,Spirit 解析第一行并创建一个向量,其中包含我感兴趣的位置的枚举。然后我必须手动解析终端符号...
enum LineItems {
NAME, AGE, UNUSED
};
struct CsvLine {
string name;
int age;
};
using Column = std::string;
using CsvFile = std::vector<CsvLine>;
template<typename It>
struct CsvGrammar: qi::grammar<It, CsvFile(), qi::locals<std::vector<LineItems>>, qi::blank_type> {
CsvGrammar() :
CsvGrammar::base_type(start) {
using namespace qi;
static const char colsep = ',';
start = qi::omit[header[qi::_a = qi::_1]] >> eol >> line(_a) % eol;
header = (lit("Name")[phx::push_back(phx::ref(qi::_val), LineItems::NAME)]
| lit("Age")[phx::push_back(phx::ref(qi::_val), LineItems::AGE)]
| column[phx::push_back(phx::ref(qi::_val), LineItems::UNUSED)]) % colsep;
line = (column % colsep)[phx::bind(&CsvGrammar<It>::convertFunc, this, qi::_1, qi::_r1,
qi::_val)];
column = quoted | *~char_(",\n");
quoted = '"' >> *("\"\"" | ~char_("\"\n")) >> '"';
}
void convertFunc(std::vector<string>& columns, std::vector<LineItems>& positions, CsvLine &csvLine) {
//terminal symbol parsing here, and assign to csvLine struct.
...
}
private:
qi::rule<It, CsvFile(), qi::locals<std::vector<LineItems>>, qi::blank_type> start;
qi::rule<It, std::vector<LineItems>(), qi::blank_type> header;
qi::rule<It, CsvLine(std::vector<LineItems>), qi::blank_type> line;
qi::rule<It, Column(), qi::blank_type> column;
qi::rule<It, std::string()> quoted;
qi::rule<It, qi::blank_type> empty;
};
这里是full source。
如果头解析器可以准备一个vector<rule<...>*> 而“行解析器”只使用这个向量来解析自己呢?一种高级的nabialek trick(我一直在尝试,但我做不到)。
或者有没有更好的方法来用 Spirit 解析这种 CSV? (任何帮助表示赞赏,在此先感谢您)
【问题讨论】:
标签: c++ csv boost boost-spirit