如何消除这个额外的因素

How to eliminate this extra element?

本文关键字:何消      更新时间:2023-10-16

我正在编写一个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)。知道怎么解决这个问题吗?

面向行输入的通常解决方案是按行读取,然后解析每一行:

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),然后使用价值。在读取值之前进行测试没有任何意义(如你所见)

好的,我知道了。文本文件的最后一行不包含换行符,这就是计算in_file的原因到true的最后一行

我想我应该计算文件的行数,然后用a替换while(in_file)for循环。

如果有人有更好的主意,请贴出来,我会接受的。

更新

修复结果相当简单,只需检查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将是空的,所以只要我们检查一下就可以了。