繁体   English   中英

读取一个csv文件并将其所有数据添加到C++中的向量中

[英]read a csv file and and add its all data into vector in c++

例如添加以下 CSV 数据:

在此处输入图片说明

我正在尝试将 CSV 文件添加到二维数组字符串向量中并获取每列的总和。 以下程序无法正常工作,

vector<string> read_csv(string filename){

    vector<string> result;
    fstream fin;
    fin.open(filename, ios::in);

    if(!fin.is_open())
        throw std::runtime_error("Could not open file");

    std::string line, colname;
    int val;

    // Read the column names
    if(fin.good())
    {
        std::getline(fin, line);
        std::stringstream ss(line);
        while(std::getline(ss, colname, ',')){
            result.push_back(colname);
            cout << colname << endl;
        }
    }

    while(std::getline(fin, line))
    {
        std::stringstream ss(line);
        int colIdx = 0;
        while(ss >> val){

            if(ss.peek() == ',') ss.ignore();
            colIdx++;
        }
    }
    fin.close();
    return result;
}

当我试图通过向量时,我没有得到正确的结果。 它只显示列名。

for (int i = 0; i < vectorCsv.size(); ++i) 
{
        cout << vectorCsv[i] << endl;
}

我找不到错误是在 read_csv() 函数中还是在 forloop 中。 谢谢你看这个问题。

在您的 while 循环中,您从未将任何值推送到您的向量。

看起来您拥有将 csv 读入向量所需的一切。 唯一的问题是您停在列名处。

// Read the column names
    if(fin.good())
    {
        std::getline(fin, line);
        std::stringstream ss(line);
        while(std::getline(ss, colname, ',')){
            result.push_back(colname);
            cout << colname << endl;
        }
    }

尝试将我上面复制的代码更改为:

// Read the column names
    while(std::getline(fin, line))
    {
        std::getline(fin, line);
        std::stringstream ss(line);
        while(std::getline(ss, colname, ',')){
            result.push_back(colname);
            cout << colname << endl;
        }
    }
  1. 不要尝试创建std::string的向量,这可能不是很有效 - 每个字符串被分别分配和取消分配。
  2. 不要自己阅读 CSV - 你在重新发明轮子。 使用现有的库。 这是一个关于在 Software Recommendations StackExchange 中找到一个的问题:

    现代 C++ CSV 阅读器(也可能是编写器)库

我不敢相信我们正在使用一个库来完成如此简单的事情,比如将std::string拆分为标记。

长期以来,C++ 具有专门为此目的而设计的内置和专用功能,用于对字符串进行标记(将字符串拆分为标记)。 并且因为这样一个专为此目的而设计的简单专用功能可用,所以应该使用它。 不需要外部库或复杂的结构。 只需使用std::sregex_token_iterator

这是一个迭代器(像许多其他迭代器一样),它迭代字符串的标记(子字符串)。 所以,我们想要什么。

然后我们可以使用std::vector的 range 构造函数来编写如下简单的内容:

std::vector tokens(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));

因此,我们定义了一个名为“tokens”的std::vector类型的变量(使用 CTAD 会自动推导出向量的类型)。 我们使用它的范围构造函数并提供一个开始和一个结束迭代器。 开始迭代器是std::sregex_token_iterator而结束迭代器是其默认初始化的对应物。

为了将这样的向量放入二维向量中,我们使用外部向量emplace_back函数并对内部向量进行就地构造。

所以你用 2 个语句阅读了整个 CSV 文件

  • 一个简单的 for 循环
  • 使用std::sregex_token_iterator返回一个简单的std::sregex_token_iterator
        // We will read all lines of the source file with a simple for loop and std::getline
        for (std::string line{}; std::getline(csvFile, line); ) {

            // We will split the one big string into tokens (sub-strings) and add it to our 2D array
            csvData.emplace_back(std::vector<std::string>(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));
        }

那么,为什么要使用一个库来完成一个可以用 2 个语句完成的简单任务呢? 我个人无法理解这一点。 因此,我发现已接受答案中的建议完全错误。 但是,为了避免开始宗教讨论:这是我非常个人的拙见,每个人都可以为所欲为。

请查看一个完整的工作示例,它只需几行代码即可解决您的问题。 . .

#include <iostream>
#include <fstream>
#include <vector>
#include <regex>

const std::string csvFileName{ "r:\\csv.csv" };
const std::regex delimiter{ "," };

int main() {

    // Open the file and check, if it could be opened
    if (std::ifstream csvFile(csvFileName); csvFile) {

        // This is our "2D array string vector" as described in your post
        std::vector<std::vector<std::string>> csvData{};


        // Read the complete CSV FIle into a 2D vector ----------------------------------------------------
        // We will read all lines of the source file with a simple for loop and std::getline
        for (std::string line{}; std::getline(csvFile, line); ) {

            // We will split the one big string into tokens (sub-strings) and add it to our 2D array
            csvData.emplace_back(std::vector<std::string>(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));
        }
        // -------------------------------------------------------------------------------------------------


        // This is for summing up values
        double DP{}, Dta{}, Dts{};

        // Iterate in a simple for loop through all elements of the 2D vector, convert the vlaues to double and sum them up
        for (size_t i = 1U; i < csvData.size(); ++i) {

            DP += std::stod(csvData[i].at(1));
            Dta += std::stod(csvData[i].at(2));
            Dts += std::stod(csvData[i].at(3));
        }

        // Sho the result to the user
        std::cout << "\nSums:  DP: " << DP << "  Dta: " << Dta << "  Dts: " << Dts << "\n";
    }
    else { // In case that we could not open the source file
        std::cerr << "\n*** Error. Could not open file " << csvFileName << "\n\n";
    }
    return 0;
}

但正如所说,每个人都可以为所欲为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM