因此,解决方案是使用代理类。您的 Cell 的抽象。
如果您有一个包含 2 个值的单元格,那么我们将定义一个具有 2 个值的类,并覆盖该类的插入器和提取器运算符。只有类应该知道如何读取和写入其数据。
读取诸如“1,2”之类的内容的提取器相当简单。这是
stream >> value1 >> c >> value2;
所以,我们提取一个整数,然后是一个逗号,然后又是一个整数。所以,真的很简单。而且,由于该文件是由 Matlab 生成的,因此我们依赖于正确的输入格式。
因此,通过将大问题分解为小问题,我们可以找到更简单的解决方案。
接下来,如果我们有像1,1 1,2 1,3 1,4 这样的完整行,如何阅读。如果你用sn 替换x,y,那么你可以写
stream >> s1 >> s2 >> s3 >> s3;
但是如果元素的数量是未知的,那么我们需要遍历所有的值。为此,我们有std::istream_iterator。请阅读here。只要输入可用,它基本上会为给定类型调用提取器运算符>>。所以,如果类型是Cell,它会重复调用>> cell[n]。
如果我们定义一个std::vector,我们可以使用它的范围构造函数来填充std::vector。请阅读here 中关于 5 号构造函数的信息。开始迭代器将是 std::istream_operator 的构造函数,结束迭代器将是通过 {} 构造的默认 std::istream_iterator。见Constructor number 1。
这将导致:
std::vector<Cell> lineVector(std::istream_iterator<Cell>(lineStream), {})
请注意,我们对std::vector<Cell>```=CV```` 使用 typedef(使用),这使编写更简单。这样,我们得到:
CV lineVector(std::istream_iterator<Cell>(lineStream), {})
好的,现在我们有了完整的解析行。
此外,我们还有一个结果std::vector,其中包含上述所有数据。
要将这样的解析行添加到生成的“单元格”-vector,我们现在可以使用push_back 函数。但我们可以更好地使用emplace_back 函数,避免临时线向量并进行就地构造。
所有这一切最终将在:
cells.emplace_back(CV(std::istream_iterator<Cell>(lineStream), {}));
所以,我们将有一个非常简单的机制来解析完整的文件。
请看下面的具体解决方案。
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
std::istringstream testStream{R"(1,1 1,2 1,3 1,4
2,1 2,2 2,3 2,4
3,1 3,2 3,3 3,4
4,1 4,2 4,3 4,4)"};
// Proxy class to abstract a Cell
struct Cell {
int value1{};
int value2{};
// Overwrite exctractor
friend std::istream& operator >> (std::istream& is, Cell& c) {
char comma;
return is >> c.value1 >> comma >> c.value2;
}
// Overwrite inserter
friend std::ostream& operator << (std::ostream& os, const Cell& c) {
return os << c.value1 << ',' << c.value2;
}
};
using CV = std::vector<Cell>;
int main() {
// The target data
std::vector<CV> cells{};
// Read and parse complete source file.
// Readd all lines of the source file
for (std::string line{}; std::getline(testStream, line); ) {
// Put the line into a stringstream
std::istringstream lineStream{ line };
// Parse the line data and add the result to our cells vector
cells.emplace_back(CV(std::istream_iterator<Cell>(lineStream), {}));
}
// Show result on console
// Go through all lines
for (const CV& cv : cells) {
// Go through all columns
for (const Cell& c : cv) std::cout << c << '\t';
std::cout << '\n';
}
return 0;
}
请注意:我们主要只有 3 行完成所有工作。
如果您还有其他问题,请提出。