从C+中的CSV文件中提取某些列+; 我想知道如何从C++中的CSV文件中提取/跳过某些列,如代码>年龄>代码>和代码>重量。
加载整个csv文件后提取所需信息是否更有意义(如果内存没有问题) 编辑:如果可能,我希望有一个阅读、打印和修改部分 如果可能,我只想使用STL。我的测试csv文件的内容如下所示:从C+中的CSV文件中提取某些列+; 我想知道如何从C++中的CSV文件中提取/跳过某些列,如代码>年龄>代码>和代码>重量。,c++,csv,data-manipulation,C++,Csv,Data Manipulation,加载整个csv文件后提取所需信息是否更有意义(如果内存没有问题) 编辑:如果可能,我希望有一个阅读、打印和修改部分 如果可能,我只想使用STL。我的测试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++程序加载测试.CSV < /C>文件,在屏幕上打印文件的内
*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++程序加载<代码>测试.CSV < /C>文件,在屏幕上打印文件的内容:
#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;
}
}
#包括
#包括
#包括
#包括
#包括
#包括
void readCSV(标准::矢量和数据,标准::字符串文件名);
无效打印CSV(常量标准::矢量和数据);
int main(int argc,字符**argv){
std::string file_path=“./test.csv”;
std::矢量数据;
readCSV(数据、文件和路径);
打印CSV(数据);
返回0;
}
void readCSV(标准::矢量和数据,标准::字符串文件名){
字符分隔符=';';
std::字符串行;
std::字符串项;
std::ifstream文件(文件名);
while(std::getline(文件,行)){
std::向量行;
std::stringstream字符串\u流(行);
while(std::getline(字符串、项、分隔符)){
行。推回(项目);
}
数据。推回(世界其他地区);
}
file.close();
}
void printCSV(常量标准::向量和数据){
用于(标准::矢量行:数据){
用于(标准::字符串项:行){
std::cout基本上我已经在一个类似的线程中回答了这个问题。但是无论如何,我将用不同的方法展示一个现成的解决方案,并在这里进行一些解释
提示:您应该更加熟悉面向对象编程。并仔细考虑您的设计。在读写函数中,您创建了一个对文件或对std::cout
的不必要的依赖关系-因此,您不应该先移交文件名,然后在函数中打开文件,而是使用流我用C++ IO工具创建的函数,不管我们从文件还是代码> STD::ISTIGISSWORT 或写入<代码> STD::CUT< /COD>或文件流。
所有操作都将通过(过载的)提取器和插入器操作符进行处理
因此,由于我希望代码更灵活一些,我将我的结构作为模板,以便能够放入选定的列中,并将相同的结构重新用于其他列组合
如果希望固定选定列,则可以使用template
删除该行,并将std::vector selectedFields{{{columns…}};
替换为std::vector selectedFields{{{1,2};
稍后,我们对模板使用使用,以便于处理和理解:
// Define Dataype for selected columns age and weight
using AgeAndWeight = SelectedColumns<1, 2>;
很简单,对吧
但是由于std::getline
的附加功能,is被严重滥用于字符串的标记化。如果您查看顶部关于如何解析CSV文件的问题/答案(请参见),那么您将了解我的意思
人们使用std::getline
从原始流中读取文本行、字符串,然后将其填充到std::istringstream
中,并再次使用带分隔符的std::getline
将字符串解析为标记。奇怪
但是,很多年以来,我们有一个专门的、特殊的函数来标记字符串,特别是为此而显式设计的
std::sregex\u令牌\u迭代器
既然我们有这样一个专用功能,我们就应该简单地使用它
这是一个迭代器。对于在字符串上进行迭代,因此函数名以s开头。开始部分定义了我们应该操作的输入范围,结束部分是默认构造的,然后输入字符串中应该匹配/不应该匹配的内容有一个std::regex。匹配策略的类型与最后一个参数一起给出
- 0-->提供我在正则表达式中定义的内容,并(可选)
- -1-->根据正则表达式给出不匹配的内容
我们可以使用该迭代器将令牌存储在std::vector
中。std::vector
有一个范围构造函数,它将2个迭代器作为参数,并将第一个迭代器和第二个迭代器之间的数据复制到std::vector
std::vector tokens(std::sregex_token_iterator(s.begin(), s.end(), re, -1), {});
将变量“tokens”定义为std::vector,并使用std::vector的所谓范围构造函数。请注意:我使用的是C++17,可以在不使用模板参数的情况下定义std::vector
。编译器可以从给定的函数参数推断参数。此功能称为CTAD(“类模板参数推导”)
此外,您可以看到我没有显式地使用“end()”-迭代器
此迭代器将使用正确类型的空括号括起的默认初始值设定项构造,因为由于std::vector
构造函数要求它,它将被推断为与第一个参数的类型相同
您可以读取一行中任意数量的令牌,并将其放入std::vector
但您可以做得更多。您可以验证您的输入。如果您使用0作为最后一个参数,您可以定义一个甚至验证您的输入的std::regex
。并且您只能获得有效的令牌
总的来说,专用功能的使用优于误用的std::getline
,人们应该简单地使用它
有些人抱怨函数开销,他们是对的,但他们中有多少人在使用大数据。即使这样,方法也可能是使用string.find
和string.substring
或std::stringview
或其他方法
那么,现在来进一步探讨话题
在提取器中,我们首先读取com
std::vector<std::string> data{};
for (char* token = std::strtok(const_cast<char *>(line.data()), ","); token != nullptr; token = std::strtok(nullptr, ","))
data.push_back(token);
std::vector tokens(std::sregex_token_iterator(s.begin(), s.end(), re, -1), {});