有多种方法可以做到这一点。首先想到的是将您的.csv 文件读入vector<string> 的向量中,以便将每个行/列值存储在一个二维数组中,例如向量的向量容器。 (例如std::vector<std::vector<string>> array;)。这使您可以使用getline 和stringstream 在读取的行上轻松解析.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() 中减去当前迭代器,但适用的迭代器存在限制。好的旧索引不在乎。
查看一下,如果您还有其他问题,请告诉我。