簡體   English   中英

在 C++ 中從 CSV 文件中提取數據

[英]Extracting data from a CSV file in C++

我的測試 csv 文件的內容如下所示:

    *test.csv*

    name;age;weight;height;test
    Bla;32;1.2;4.3;True
    Foo;43;2.2;5.3;False
    Bar;None;3.8;2.4;True
    Ufo;32;1.5;5.4;True

我使用以下在屏幕上打印文件內容的 C++ 程序加載test.csv文件:

#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>

void readCSV(std::vector<std::vector<std::string> > &data, std::string filename);
void printCSV(const std::vector<std::vector<std::string>> &data);

int main(int argc, char** argv) {
    std::string file_path = "./test.csv";
    std::vector<std::vector<std::string> > data;
    readCSV(data, file_path);
    printCSV(data);
    return 0;
}

void readCSV(std::vector<std::vector<std::string> > &data, std::string filename) {
    char delimiter = ';';
    std::string line;
    std::string item;
    std::ifstream file(filename);
    while (std::getline(file, line)) {
        std::vector<std::string> row;
        std::stringstream string_stream(line);
        while (std::getline(string_stream, item, delimiter)) {
            row.push_back(item);
        }
        data.push_back(row);
    }
    file.close();
}

void printCSV(const std::vector<std::vector<std::string> > &data) {
    for (std::vector<std::string> row: data) {
        for (std::string item: row) {
            std::cout << item << ' ';
        }
        std::cout << std::endl;
    }
}

我有以下問題:

  • 如何僅加載age == 32
  • 例如,如何僅加載nameweight列?
  • 如何排除包含None行?
  • 如何跳過文檔的第一行?

加載整個 csv 文件后提取所需信息是否更有意義(如果內存不成問題)? 如果可能,我只想使用 STL。

您能提供的任何幫助將不勝感激

你可以嘗試一些 csv 庫,但如果你想用自定義代碼來做到這一點,那么

printCSV您要求cin輸入列名

將其保存在變量中

在此代碼for (std::vector<std::string> row: data)

當第一次循環運行時,再次檢查每個輸入的item

然后在第二個循環中保留一個索引,因此您可以跳過列號

僅打印兩列的示例代碼

void printCSV(const std::vector<std::vector<std::string> > &data) {
    int col = 0;
    std::vector<std::string> column_filter;
    std::vector<int> column_index;
    column_filter.push_back("name");
    column_filter.push_back("weight");
    int row1 =0;

    for (std::vector<std::string> row: data) {
        col = 0;
        if(row1==0) {
            int col1 = 0;
            for (std::string item: row) {
                for (std::string colname: column_filter){
                    if(item.compare(colname)==0) {
                        column_index.push_back(col1);
                    }
                }
                col1++;
            }

        }

        for (std::string item: row) {
            int found =0;
            for (int index: column_index) {
                if(index==col) found = 1;
            }
            if(found==1)
            std::cout << item << ' ';
            col++;
        }
        std::cout << std::endl;
        row1++;
    }
}

輸出

name weight 
Bla 1.2 
Foo 2.2 
Bar 3.8 
Ufo 1.5 

在你關閉之前。 這里所有答案都在一個文件中。 但我會在你的單個問題中解釋,然后稍后。

#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <fstream>
#include <regex>
#include <algorithm>
#include <iterator>

// Save typing Work
using Rec = std::vector<std::string>;
std::regex delimiter{ ";" };

// Proxy class for easier input and output
struct Record {
    // Our data for one record
    Rec data{};

    // Overwrite extractor operator
    friend std::istream& operator >> (std::istream& is, Record& r) {
        // Read on complete line from the input stream, and check, if the read was successfull
        if (std::string line{}; std::getline(is, line)) {

            // If there is something in our data vector already, delete it
            r.data.clear();
            // Now, in one statement, split the string into tokens and copy the result into our data vector
            std::copy(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}, std::back_inserter(r.data));
        }
        return is;
    }

    // Overwrite inserter for easier output
    friend std::ostream& operator << (std::ostream& os, const Record& r) {
        std::copy(r.data.begin(), r.data.end(), std::ostream_iterator<std::string>(os,"\t"));
        return os;
    }
};

// Proxy for the complete CSV file
struct Roster {
    // The header
    Rec header{};
    // All records of the CSV file
    std::vector<Record> records{};

    friend std::istream& operator >> (std::istream& is, Roster& r) {
        // Read on complete line from the input stream, and check, if the read was successfull
        if (std::string line{}; std::getline(is, line)) {
            // So, we just have read the header
            // Now, in one statement, split the string into tokens and copy the result into the header
            r.header.clear();
            std::copy(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}, std::back_inserter(r.header));

            // Now, in one statement, read all lines, split the string into tokens and copy the result into our record vector
            r.records.clear();
            std::copy(std::istream_iterator<Record>(is), {}, std::back_inserter(r.records));
        }
        return is;
    }

    // Overwrite inserter for easier output
    friend std::ostream& operator << (std::ostream& os, const Roster& r) {
        std::copy(r.records.begin(), r.records.end(), std::ostream_iterator<Record>(os, "\n"));
        return os;
    }
};

int main() {

    // Open CSV file and check, if it could be opened
    if (std::ifstream csvFileStream("r:\\test.csv"); csvFileStream) {

        Roster roster{}; 

        // Read the complete CSV file
        csvFileStream >> roster;

        // Show all read data on std::cout
        std::cout << roster;

        // All records with age ==32
        std::cout << "\n\nAge 32\n";
        std::vector<Record> age32{};
        std::copy_if(roster.records.begin(), roster.records.end(), std::back_inserter(age32), [](const Record& r) { return r.data[1] == "32"; });
        for (const Record& r : age32) std::cout << r << "\n";

        // Or
        std::cout << "\n\nAge 32   Option 2\n";
        csvFileStream.clear(); csvFileStream.seekg(std::ios::beg); age32.clear();
        std::copy_if(std::istream_iterator<Record>(csvFileStream), {}, std::back_inserter(age32), [](const Record& r) { return r.data[1] == "32"; });
        for (const Record& r : age32) std::cout << r << "\n";

        // Get Name and weight columns
        std::cout << "\n\nweight and columns\n";
        std::vector<std::vector<std::string>> nameAndWeight{};
        std::transform(roster.records.begin(), roster.records.end(), std::back_inserter(nameAndWeight), 
            [](const Record& r) { std::vector<std::string>rec{ r.data[0], r.data[2] } ; return rec; });

        for (const std::vector<std::string>& r : nameAndWeight) std::cout << r[0] << "\t" << r[1] << "\n";

        // Everything but none
        std::cout << "\n\nEverything but none\n";
        std::vector<Record> notNone{};
        std::copy_if(roster.records.begin(), roster.records.end(), std::back_inserter(notNone), [](const Record& r) { return r.data[1] != "None"; });
        for (const Record& r : notNone) std::cout << r << "\n";

    }
    else {
        std::cerr << "\n*** Error: Could not open source file\n";
    }
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM