Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从C+中的CSV文件中提取某些列+; 我想知道如何从C++中的CSV文件中提取/跳过某些列,如代码>年龄>代码>和代码>重量。_C++_Csv_Data Manipulation - Fatal编程技术网

从C+中的CSV文件中提取某些列+; 我想知道如何从C++中的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>文件,在屏幕上打印文件的内

加载整个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>文件,在屏幕上打印文件的内容:

#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), {});