簡體   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