如何消除这个额外的元素?

时间:2014-07-24 17:41:20

标签: c++ file io

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

2 个答案:

答案 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_fileparser) 值。读取值之前的测试并不意味着什么 (正如你所见)。

答案 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将为空,所以只要我们检查一下,我们就会没事。