【发布时间】:2011-02-24 13:22:19
【问题描述】:
对我来说,为表格文本文件创建格式化数据读取/写入函数的最佳方式是什么。说一些电话,例如:
readElement(i,j)
insertRow(elem[])
readColHeaders()
我想知道是否有任何现有的包装器可以做到这一点?
内部格式是制表符间隔数据或 CSV。
Thnx-Egon
【问题讨论】:
对我来说,为表格文本文件创建格式化数据读取/写入函数的最佳方式是什么。说一些电话,例如:
readElement(i,j)
insertRow(elem[])
readColHeaders()
我想知道是否有任何现有的包装器可以做到这一点?
内部格式是制表符间隔数据或 CSV。
Thnx-Egon
【问题讨论】:
有很多 csv 阅读器,但我从来没有找到好的东西。
最简单的方法是使用 boost::tokenize 从你的文件中填充一个向量
要生成 sur 文件,迭代向量
【讨论】:
对于 C 或 C++,没有“标准”的 csv 读取器/写入器。这并不意味着你不能找到一些预先存在的库代码来使用,但是没有一个库来统治它们。在我的工作中,我们大量使用 csv 文件,所以我继续使用自己的文件,以便尽可能适合我的工作流程。如果你也想做自己的事情,我可以告诉你我在图书馆里做过的一些事情,效果相当不错:
我将数据保存为 boost::any 向量的向量。我让用户在构造函数中指定数据的格式,类似于将格式传递给 scanf 的方式。这使用户不必进行自己的演员表。我使用 boost::tokenize 和 boost::lexical_cast 来进行实际的拆分和转换。如果您的 csv 文件无法放入内存,这显然不会很好,但这对我来说很少有问题。
我可以有一个模板化的 get() 来执行 any_cast 并返回正确的数据。
我有一个列名哈希到它们的索引,以便支持按列名查找,而不仅仅是位置查找
我允许用户指定某些列组合的“主键”,然后保留一个散列,这样对于每一行,您都有一个键 -> 行号中的值的映射。例如,如果您正在阅读股票数据,您可能希望根据 CUSIP 或股票代码来查找行,而不是遍历整个数据来查找您的行。
让用户指定大小提示,以便您可以在存储中保留()
让用户指定回调函数,以便他可以在您读/写时处理和过滤他不想要的行
允许用户指定文件在读/写时是否需要锁定
允许用户为文件中没有标题的文件传入自己的列标题
不要进入语言辩论,但这个库实际上是我最初在 perl 中所做的一些东西的移植,如果它不是在 perl 中编写起来容易 10 倍,用户友好度提高 10 倍,那该死的。如果可以的话,我不建议在 C++ 中进行 csv 处理。
【讨论】:
要将制表符分隔的表格读入字符串向量的向量...
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
typedef std::vector<std::string> StringVec;
typedef std::vector<StringVec> RowVec;
RowVec readRows(std::istream& f) {
std::string line;
RowVec rows;
while (std::getline(f, line)) {
rows.push_back(StringVec());
std::string entry;
std::istringstream linestrm(line);
while (std::getline(linestrm, entry, '\t')) {
rows.back().push_back(entry);
}
}
return rows;
}
int main() {
std::istringstream textFile("a\tb\tc\n1\t2\t3");
RowVec rows = readRows(textFile);
std::cout << rows.size() << std::endl;
std::cout << rows[0][0] << std::endl;
std::cout << rows[1][2] << std::endl;
return 0;
}
【讨论】:
如果您的数据很小(例如小于几百兆字节),我会将整个文件读入内存。为此,您可以将其存储在像boost::numeric::ublas::matrix<std::string> 这样的字符串矩阵或像std::vector<std::vector<std::string> > 这样的向量向量中
Boost.Spirit 提供了一种非常好的方法来将这种类型的文本数据解析为这些结构。这归结为一个解析命令,如:
boost::spirit::qi::phrase_parse(
begin,
end,
// parse rule:
*(char_ - '\t') % '\t'
// end parse rule
space,
vec);`
更多精神例子在这里:http://www.boost.org/doc/libs/1_46_0/libs/spirit/doc/html/spirit/qi/tutorials.html
【讨论】: