从 x 列到 y 列以及从第 1 行到第 2 行 c++ 提取 csv 数据

Posted

技术标签:

【中文标题】从 x 列到 y 列以及从第 1 行到第 2 行 c++ 提取 csv 数据【英文标题】:Extract csv data from column x to column y, and from row 1 to row 2 c++ 【发布时间】:2018-03-08 20:33:15 【问题描述】:

我有一个 .csv 文件,比如说 1000 行和 1200 列。

如何从所需的列中提取数据,比如 67,到另一列,比如 890。 同时从一行,比如说 9,到另一行,比如说 789,然后用 C++ 将数据导出为新的 csv 文件?

我还是初学者,但熟悉 for 或 while 循环,我可以读取文件。

#include <iostream>
#include <fstream>
#include <string>

using namespace std;


int main() 

    ifstream csvFile;

    csvFile.open("../example.csv"); 

    if (csvFile.is_open())
        

    string line;

    while(getline(csvFile, line))
    

    //what to do here

    
        

    else 

    cout << "Sorry, the file could not be openend." <<endl;

    return -1;

    

    csvFile.close();

    return 0;

    

编辑 例如源 csv 文件:

a,1,11,111
b,2,22,222
c,3,33,333
d,4,44,444

假设我们只想要从第 2 列到第 3 列以及从第 2 行到第 3 行,那么结果是一个新的 csv 文件,如下所示:

2,22
3,33

【问题讨论】:

【参考方案1】:

有多种方法可以做到这一点。首先想到的是将您的.csv 文件读入vector&lt;string&gt; 的向量中,以便将每个行/列值存储在一个二维数组中,例如向量的向量容器。 (例如std::vector&lt;std::vector&lt;string&gt;&gt; array;)。这使您可以使用getlinestringstream 在读取的行上轻松解析.csv 文件(以',' 分隔)。

然后您可以编写一个提取函数,该函数引用您存储的 csv 值并使用基于范围的迭代器对各个向量和字符串进行迭代。此时,只需保留行索引和列索引,并在所需范围内输出所需范围和列之间的所有行值即可。一个简单的函数看起来类似于:

 void extract (vector<vector<string>>const & array, size_t r1, size_t c1,
                size_t r2, size_t c2)

    size_t ridx = 0;                    /* row index */
    for (auto& row : array)            /* range based row iterator */
        size_t cidx = 0;                /* column index */
        if (r1 <= ridx && ridx <= r2)  /* if in row range */
            for (auto& col : row)      /* range based col iterator */
                if (c1 <= cidx && cidx <= c2)  /* if in col range */
                    if (cidx > c1)      /* if greater than 1st */
                        cout << ",";    /* output separator */
                    cout << col;        /* output value */
                
                cidx++;                 /* increment col index */
            
            cout << "\n";               /* output newline */
        
        ridx++;                         /* increment row index */
        if (ridx > r2)                  /* break if row > r2 */
            break;
    

您可以让它创建一个二级字符串向量以返回以供进一步处理,或者您可以像上面那样简单地输出值(或写入另一个文件)。

将各个部分放在一个简短的示例中,该示例读取您的 csv 文件,并在您的问题中显示的第 1 行、第 1 行和第 2 行和第 2 行之间输出,您可以执行以下操作:

#include <iostream>
#include <fstream>
#include <sstream>

#include <string>
#include <vector>

using std::ifstream;
using std::cout;
using std::cerr;
using std::string;
using std::stringstream;
using std::vector;

void extract (vector<vector<string>>const & array, size_t r1, size_t c1,
                size_t r2, size_t c2)

    size_t ridx = 0;                    /* row index */
    for (auto& row : array)            /* range based row iterator */
        size_t cidx = 0;                /* column index */
        if (r1 <= ridx && ridx <= r2)  /* if in row range */
            for (auto& col : row)      /* range based col iterator */
                if (c1 <= cidx && cidx <= c2)  /* if in col range */
                    if (cidx > c1)      /* if greater than 1st */
                        cout << ",";    /* output separator */
                    cout << col;        /* output value */
                
                cidx++;                 /* increment col index */
            
            cout << "\n";               /* output newline */
        
        ridx++;                         /* increment row index */
        if (ridx > r2)                  /* break if row > r2 */
            break;
    


int main (int argc, char **argv) 

    string line;
    vector<vector<string>> array;

    if (argc < 2) 
        cerr << "error: insufficient input.\n"
                "usage: " << argv[0] << " filename\n";
        return 1;
    

    ifstream f (argv[1]);   /* open file */
    if (!f.is_open()) 
        perror (("error while opening file " + string(argv[1])).c_str());
        return 1;
    

    while (getline (f, line))          /* read each line */
        string val;                     /* string to hold value */
        vector<string> row;             /* vector for row of values */
        stringstream s (line);          /* stringstream to parse csv */
        while (getline (s, val, ','))   /* for each value */
            row.push_back (val);        /* add to row */
        array.push_back (row);          /* add row to array */
    
    f.close();

    cout << "complete array\n\n";           
    for (auto& row : array)            /* iterate over rows */
        for (auto& val : row)           /* iterate over vals */
            cout << val << "  ";        /* output value      */
        cout << "\n";                   /* tidy up with '\n' */
    

    cout << "\nextracted array\n\n";
    extract (array, 1, 1, 2, 2);        /* extract from 1,1 to 2,2 */

    return 0;

注意:基于范围的循环是 C++11 的一项功能,因此请在编译字符串中添加 -std=c++11

您不必将整个文件读入存储。您可以在初始读取行期间轻松保持行数和列数,并使用stringstream 解析列,并且只用您希望输出的值填充array,或者只输出当时的值,但是通过将extract 例程封装在一个函数中,您可以根据需要对 csv 文件的多个不同范围进行操作。这完全取决于你。完整读取只是让您可以选择输出文件的尽可能多的不同部分,而无需对原始文件执行多次 I/O。

使用/输出示例

$ ./bin/iostream_sstream_csv dat/extract.csv
complete array

a  1  11  111
b  2  22  222
c  3  33  333
d  4  44  444

extracted array

2,22
3,33

可能有更多的 C++ 方法可以将所需的行和列索引括起来,而不是保持简单的行索引和列索引,但每次都有效。您可以查看distance() 或从您的vector.begin() 中减去当前迭代器,但适用的迭代器存在限制。好的旧索引不在乎。

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

【参考方案2】:

我想主要问题是如何从给定的列/原始数据中捕获数据/变量: 1.需要定义“范围”和它

2 用“value2()”取数据

关于外观,它不能“同时”:您必须确定程序目标。谢谢!

很抱歉,这段代码插入不太习惯,所以我放了一张图片:

enter image description here

【讨论】:

目标是从 csv 源文件的总范围中选择一个定义的范围,然后将这些数据写入一个新的 csv 文件 或者只将整个csv文件分割成指定的列数,然后将这些生成的文件写入csv文件,然后可以在许多在线服务网站的帮助下进行正常的行分割 我在想两个嵌套的for循环,外循环取水平范围,内循环取垂直范围 非常好,有两个最佳循环。除了为整个 fike 获得的范围之外,请考虑再增加一个范围,以处理每个单元格值

以上是关于从 x 列到 y 列以及从第 1 行到第 2 行 c++ 提取 csv 数据的主要内容,如果未能解决你的问题,请参考以下文章

蓝桥杯国赛---质数行者(3维dp)

蓝桥杯国赛---质数行者(3维dp)

第十一届蓝桥杯(国赛)——质数行者

第十一届蓝桥杯(国赛)——质数行者

Python从第二行到第十五行读取文本文件[关闭]

diff 命令详解