如何从 CSV 获取数据并将其存储在 C++ 中的表对象中



所以基本上我希望能够打开一个CSV文件并根据该文件中的数据构造一个表对象。

以下是数据在 CSV 文件中的外观示例:

year,category,winner,entity
INT,STRING,BOOL,STRING
2015,CHEF OF THE YEAR,FALSE,John Doe
2015,CHEF OF THE YEAR,FALSE,Bob Brown
2015,CHEF OF THE YEAR,TRUE, William Thorton
2015,CHEF OF THE YEAR,FALSE,Jacob Smith

第一行列出表中所有属性的名称,第二行列出属性类型。

我想我必须实现一个表和行类才能正常工作。我感到困惑的是存储具有不同列值属性类型的表的数据结构,以及所述表和行类的布局究竟是什么样子的。

任何帮助将不胜感激!

好的,我建议你使用 https://github.com/vincentlaucsb/csv-parser

对于您的情况,您只应该删除带有类型的行,因为 C++ 无法动态生成类(所有类型都应该在编译时已知(

这是您的案例的示例

#include <iostream>
#include <string>
#include "csv-parser/single_include/csv.hpp"
using namespace csv;
bool string_to_bool(std::string state)
{
if (state == "FALSE")
return false;
if (state == "TRUE")
return true;
throw std::runtime_error("incorrect input");
}
struct Data
{
int year;
std::string category;
bool winner;
std::string entity;
};
int main()
{
CSVReader reader("...enter path to your file ... /data.csv");
std::vector<Data> entities;
for (auto& row : reader)
{
Data entity;
entity.year = row["year"].get<int>();
entity.winner = string_to_bool(row["winner"].get<std::string>());
entity.category = row["category"].get<std::string>();
entity.entity = row["entity"].get<std::string>();
entities.push_back(entity);
}
}

CSV 文件

year,category,winner,entity
2015,CHEF OF THE YEAR,FALSE,John Doe
2015,CHEF OF THE YEAR,FALSE,Bob Brown
2015,CHEF OF THE YEAR,TRUE, William Thorton
2015,CHEF OF THE YEAR,FALSE,Jacob Smith

创建 CMakeLists.txt

对于安装解析器,只需执行

git clone https://github.com/vincentlaucsb/csv-parser.git 

并添加 CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(project_name)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(csv-parser)
add_executable(project_name main.cpp)
target_link_libraries(project_name csv)

项目层次结构

$ ll       
total 24
-rw-r--r--@  1 user  staff   192B Jan 26 12:14 CMakeLists.txt
drwxr-xr-x@  9 user  staff   288B Jan 26 12:14 cmake-build-debug
drwxr-xr-x  23 user  staff   736B Jan 26 11:18 csv-parser
-rw-r--r--   1 user  staff   191B Jan 26 11:54 data.csv
-rw-r--r--@  1 user  staff   871B Jan 26 12:02 main.cpp

您在评论中询问了不使用库的解决方案。您要求更多(变体数据类型(,但我首先展示了一种标准的C++方法。

我想,你已经完成了你的任务。如果您仍然感兴趣,我会给您更详细的解释。

#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <string>
#include <iterator>
#include <algorithm>
// the delimiter for the csv
const std::regex re(",");
// One DataRow from the csv file
struct DataRow {
int year{};
std::string category{};
bool winner{};
std::string entity{};
friend std::istream& operator >> (std::istream& is, DataRow& dr) {
// Read one complete line
if (std::string line{}; std::getline(is, line)) {
// Split the string, containing the complete line into parts
std::vector<std::string> part(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {});
// Convert into our local data / types
if (4U == part.size()) {
dr.year = std::stoi(part[0]);
dr.category = part[1];
dr.winner = (part[2] == "TRUE") ? true : false;
dr.entity = part[3];
}
}
return is;
}
// Simple data output
friend std::ostream& operator << (std::ostream& os, const DataRow& dr) {
return os << "nYear:     " << dr.year << "nCategory: " << dr.category << "nWinner:   " << dr.winner << "nEntity:   " << dr.entity << "n";
}
};
// This will hold all CSV data
struct CSV{
std::vector<std::string> header{};
std::vector<std::string> types{};
std::vector<DataRow> data{};
// Extractor
friend std::istream& operator >> (std::istream& is, CSV& c) {
if (std::string line{}; std::getline(is, line)) {
// Read and parse header
c.header.clear();
std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::back_inserter(c.header));
if (std::getline(is, line)) {
// Read and parse types
c.types.clear();
std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::back_inserter(c.types));
// Get all data. Read all lines and parse them
c.data.clear();
std::copy(std::istream_iterator<DataRow>(is), {}, std::back_inserter(c.data));
}
}
return is;
}
// Make some nice output
friend std::ostream& operator << (std::ostream& os, const CSV& c) {
os << "Header: ";
std::copy(c.header.begin(), c.header.end(), std::ostream_iterator<std::string>(os, "  "));
os << "nTypes:  ";
std::copy(c.types.begin(), c.types.end(), std::ostream_iterator<std::string>(os, "  "));
os << "nnData:n";
std::copy(c.data.begin(), c.data.end(), std::ostream_iterator<DataRow>(os, "  "));
return os;
}
};
std::istringstream csvFile{ R"(year,category,winner,entity
INT,STRING,BOOL,STRING
2015,CHEF OF THE YEAR,FALSE,John Doe
2015,CHEF OF THE YEAR,FALSE,Bob Brown
2015,CHEF OF THE YEAR,TRUE,William Thorton
2015,CHEF OF THE YEAR,FALSE,Jacob Smith)" };

int main() {
// Define a variable of type CSV. This will hold all data
CSV csv{};
// Read from a file and put everything into our variable
csvFile >> csv;
// Show all contents of CSV on screen
std::cout << csv;
return 0;
}````

最新更新