我正在编写一个c ++函数来读取制表符分隔文本文件的第n列,这是我所做的:
typedef unsigned int uint;
inline void fileExists (const std::string& name) {
if ( access( name.c_str(), F_OK ) == -1 ) {
throw std::string("File does not exist!");
}
}
size_t bimNCols(std::string fn) {
try {
fileExists(fn);
std::ifstream in_file(fn);
std::string tmpline;
std::getline(in_file, tmpline);
std::vector<std::string> strs;
strs = boost::split(strs, tmpline, boost::is_any_of("\t"), boost::token_compress_on);
return strs.size();
} catch (const std::string& e) {
std::cerr << "\n" << e << "\n";
exit(EXIT_FAILURE);
}
}
typedef std::vector<std::string> vecStr;
vecStr bimReadCol(std::string fn, uint ncol_select) {
try {
size_t ncols = bimNCols(fn);
if(ncol_select < 1 or ncol_select > ncols) {
throw std::string("Your column selection is out of range!");
}
std::ifstream in_file(fn);
std::string tmpword;
vecStr colsel; // holds the column of strings
while (in_file) {
for(int i=1; i<ncol_select; i++) {
in_file >> tmpword;
}
in_file >> tmpword;
colsel.push_back(tmpword);
in_file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return colsel;
} catch (const std::string& e) {
std::cerr << "\n" << e << "\n";
exit(EXIT_FAILURE);
}
}
问题是,在bimReadCol
函数中,在最后一行,在
in_file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
in_file.good()
仍评估为true
。所以,假设我有一个像这样的文本文件test.txt
:
a 1 b 2
a 1 b 2
a 1 b 2
bimReadCol("test.txt", 3)
会返回一个带有额外元素的向量(b, b, b, b)
。
知道如何解决这个问题吗?
答案 0 :(得分:1)
面向行的输入的通常解决方案是读取行 行,然后解析每一行:
std::string line;
while ( std::getline( in_file, line ) ) {
std::istringstream parser( line );
for ( int i = 1; parser >> tmpword && i <= ncol_select; ++ i ) {
}
if ( parser ) {
colsel.push_back( tmpword );
}
// No need for any ignore.
}
重要的是你必须在之后绝对测试
在使用之前输入(来自in_file
或parser
)
值。读取值之前的测试并不意味着什么
(正如你所见)。
答案 1 :(得分:0)
好的,我明白了。文本文件的最后一行不包含换行符,这就是in_file
计算的原因
到最后一行的true
。
我想我应该计算文件的行数,然后用{替换while(in_file)
for loop。
如果有人有更好的想法,请发布,我会接受。
修复结果非常简单,只需检查tmpword
是否为空:
vecStr bimReadCol(std::string fn, uint ncol_select) {
try {
size_t ncols = bimNCols(fn);
if(ncol_select < 1 or ncol_select > ncols) {
throw std::string("Your column selection is out of range!");
}
std::ifstream in_file(fn);
vecStr colsel; // holds the column of strings
std::string tmpword;
while (in_file) {
tmpword = "";
for(int i=1; i<=ncol_select; i++) {
in_file >> tmpword;
}
if(tmpword != "") {
colsel.push_back(tmpword);
}
in_file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return colsel;
} catch (const std::string& e) {
std::cerr << "\n" << e << "\n";
exit(EXIT_FAILURE);
}
}
正如@James Kanze指出的那样,即使最后一行包含换行符,in_file
仍将评估为true
,但由于我们处于文件的末尾,下一个阅读
tmpword
将为空,所以只要我们检查一下,我们就会没事。