解析具有提升精神的简单 csv 表

Parsing simple csv table with boost-spirit

本文关键字:简单 csv      更新时间:2023-10-16

我试图使用boost-spirit来解析一个相当简单的cvs文件格式。

我的csv文件看起来像这样:

测试.txt

2
5. 3. 2.
6. 3. 6.

第一个整数表示要读取的行数,每行正好由三个双精度值组成。

这就是我到目前为止得到的。

主.cpp

#include <vector>
#include <fstream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/phoenix/object/construct.hpp>
std::vector<std::vector<double>> parseFile(std::string& content)
{
    std::vector<std::vector<double>> ret;
    using namespace boost::phoenix;
    using namespace boost::spirit::qi;
    using ascii::space;
    int no;
    phrase_parse(content.begin(), content.end(),
        int_[ref(no) = _1] >> repeat(ref(no))[(double_ >> double_ >> double_)[
            std::cout << _1 << _2 << _3
        ]], space
    );
    return ret;
}
int main(int arg, char **args) {
    auto ifs = std::ifstream("Test.txt");
    std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
    parseFile(content);
}

现在,我需要的不是行std::cout << _1 << _2 << _3,而是附加包含三个值的std::vector<double>的东西。

我已经尝试过_val=construct<std::vector<double>>({_1,_2,_3}),但它不起作用。那我做错了什么?

它比您想象的要简单得多¹

std::vector<std::vector<double>> parseFile(std::string const& content) {
    namespace px = boost::phoenix; 
    using namespace boost::spirit::qi;
    int no;
    std::vector<std::vector<double>> data;
    bool ok = phrase_parse(content.begin(), content.end(),
        int_ [ px::ref(no) = _1 ] >> eol 
        >> repeat(px::ref(no)) [ repeat(3) [double_] >> (eol|eoi)],
        blank,
        data
    );
    if (!ok)
        throw std::runtime_error("Parse failure");
    return data;
}

科利鲁上观看直播。它使用自动属性传播 - Spirit最有用的功能开始 - 和blank船长而不是space,所以我们仍然可以解析eol

现在,我建议让它更简单:

住在科里鲁

bool ok = phrase_parse(
    content.begin(), content.end(),
    int_ >> eol >> *(+double_ >> (eol|eoi)) >> *eol >> eoi, 
    blank, 
    no, data
);
if (!ok && (no == data.size()))
    throw std::runtime_error("Parse failure");

或者,事实上,仅使用标准库甚至更简单:

住在科里鲁

#include <vector>
#include <iostream>
#include <fstream>
#include <iterator>
std::vector<std::vector<double>> parseFile(std::string const& fname) {
    std::vector<std::vector<double>> data;
    auto ifs = std::ifstream(fname);
    size_t no = -1;
    if (ifs >> no && ifs.ignore(1024, 'n')) {
        double a, b, c;
        while (ifs >> a >> b >> c)
            data.push_back({a, b, c});
    }
    if (!(ifs.eof() && (no == data.size())))
        throw std::runtime_error("Parse failure");
    return data;
}
int main() {
    for (auto& row : parseFile("input.txt"))
        std::copy(row.begin(), row.end(), std::ostream_iterator<double>(std::cout << "n", " "));
}

它们都成功地解析和打印:

5 3 2 
6 3 6 

¹ 提升精神:"语义行为是邪恶的"?

奖励:自动自定义属性类型

而不是不透明的向量,为什么不使用这样的结构

struct Point {
    double x,y,z;
};

并解析为std::vector<Point>.作为奖励,您基本上免费获得输出和解析器:

BOOST_FUSION_ADAPT_STRUCT(Point, x, y, z)
// parser:
auto_ >> eol >> *(auto_ >> (+eol|eoi)) >> eoi,

科里鲁现场观看