【问题标题】:How can I read CSV file in to vector in C++如何在 C++ 中将 CSV 文件读入向量
【发布时间】:2019-11-21 02:07:56
【问题描述】:

我正在做将 python 代码转换为 C++ 的项目,以获得更好的性能。该python项目名称是Advanced EAST,现在,我在.csv文件中获得了nms函数的输入数据,如下所示:

"[ 5.9358170e-04  5.2773970e-01  5.0061589e-01 -1.3098677e+00
 -2.7747922e+00  1.5079222e+00 -3.4586751e+00]","[ 3.8175487e-05  6.3440394e-01  7.0218205e-01 -1.5393494e+00
 -5.1545496e+00  4.2795391e+00 -3.4941311e+00]","[ 4.6003381e-05  5.9677261e-01  6.6983813e-01 -1.6515008e+00
 -5.1606908e+00  5.2009044e+00 -3.0518508e+00]","[ 5.5172237e-05  5.8421570e-01  5.9929764e-01 -1.8425952e+00
 -5.2444854e+00  4.5013981e+00 -2.7876694e+00]","[ 5.2929961e-05  5.4777789e-01  6.4851379e-01 -1.3151239e+00
 -5.1559062e+00  5.2229333e+00 -2.4008298e+00]","[ 8.0250458e-05  6.1284608e-01  6.1014801e-01 -1.8556541e+00
 -5.0002270e+00  5.2796564e+00 -2.2154367e+00]","[ 8.1256607e-05  6.1321974e-01  5.9887391e-01 -2.2241254e+00
 -4.7920742e+00  5.4237065e+00 -2.2534993e+00]

一个单位是 7 个数字,但前四个数字后有一个 '\n', 我想将这个 csv 文件读入我的 C++ 项目, 这样我就可以在 C++ 中做数学工作,让它更快。

using namespace std;

void read_csv(const string &filename)
{
//File pointer
fstream fin;
//open an existing file
fin.open(filename, ios::in);

vector<vector<vector<double>>> predict;

string line;
while (getline(fin, line))
{
    std::istringstream sin(line);
    vector<double> preds;
    double pred;
    while (getline(sin, pred, ']'))
    {
        preds.push_back(preds);
    }

}

}

现在...我的代码 emmmmmm 无法正常工作, 我完全不知道这个... 请帮助我将 csv 数据读入我的代码。 谢谢

【问题讨论】:

  • 搜索一个为你做这件事的图书馆。 CSV 是一种看似简单的格式,但有很多角落和特殊情况,解析起来并不简单。对于您的输入尤其如此,因为它以非常规方式格式化(似乎是 Python 脚本的某些内部数据的控制台上的直接转储)。
  • getline(fin, string, ']') 的输出提供给stringstream。丢弃第一个单词并阅读doubles 直到流结束。那是一个记录。其余部分重复。

标签: c++ csv vector nms


【解决方案1】:

不幸的是,在 C++ 中解析字符串(进而解析文件)非常乏味。

我强烈推荐使用一个库,最好是一个只有标题的库,like this one

如果你坚持自己写,也许你可以从this StackOverflow question 中获得一些关于如何在 C++ 中解析通用 CSV 文件的灵感。

【讨论】:

    【解决方案2】:

    你可以看看getdelim(',', fin, line)

    但另一个问题是那些引号,除非您 /know/ 文件总是以这种方式完全格式化,否则会变得很困难。

    我过去使用过的一个不完美的技巧,如果第一个字符是引号,那么逗号之前的最后一个字符也必须是匹配的引号,并且不能转义。

    如果不是引用,则getdelim() 更多,但getdelim 的自动分配功能意味着您必须使用另一个缓冲区。在 C++ 中,我最终得到了一个包含所有 getdelim 结果的向量,然后需要将它们连接起来以形成最终的字符串:

    std::vector<char*> gotLine;
    gotLine.push_back(malloc(2));
    *gotLine.back() = fgetch();
    gotLine.back()[1] = 0;
    bool gotquote = *gotLine.back() == '"'; // perhaps different classes of quote
    if (*gotLine.back() != ',')
     for(;;)
     {
      char* gotSub= nullptr;
      gotSub=getdelim(',');
      gotLine.push_back(gotSub);
      if (!gotquote) break;
      auto subLen = strlen(gotSub);
      if (subLen>1 && *(gotSub-1)=='"') // again different classes of quote
        if (sublen==2 || *(gotSub-2)!='\\') // needs to be a while loop
           break;
     }
    

    然后将所有这些字符串段重新连接在一起。

    请注意,getdelim 支持空字节。如果您希望内容中包含空字节,而不是由字符序列 \000\@ 表示,则需要存储 getdelim 返回的实际长度,并使用 memcpy 连接它们。

    哦,如果您允许使用 utf-8 扩展引号,它会变得非常混乱!

    本文未涵盖的情况是一个以\\"\\\\" 结尾的字符串。理想情况下,您需要同时计算前导反斜杠的数量,如果计数是偶数,则接受引号。

    请注意,这会留下取消转义引用内容的问题,即将任何\" 转换为",并将\\ 转换为\ 等。同时丢弃封闭的引号。

    最后,如果您需要处理完全任意的内容,库可能会更容易。但是,如果内容是“已知的”,你可以不用。

    【讨论】:

    • 请注意 getdelim 是一个 POSIX 特定的函数,它不会存在于例如窗户。
    • @Someprogrammerdude 公平点。我的文档只说 >
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 2021-09-18
    • 2019-07-05
    • 1970-01-01
    相关资源
    最近更新 更多