C ++如何使用fstream读取带空格的制表符分隔文件

时间:2016-10-31 05:48:42

标签: c++ fstream

我需要使用一些C ++代码来读取制表符分隔的文本文件。该文件包含三列,第二列包含带空格的字符串。以下是该文件的一些示例。

1   hellow world    uid_1
2   good morning    uid_2

以下是我需要用来读取文件的C ++。但是,当命中字符串中的空格时,它无法正确读取文件。

有关修改while循环以使其有效的任何建议吗?我不熟悉C ++。请提供详细的代码。谢谢!

#include <Rcpp.h>
#include <iostream>
#include <fstream>
#include <string>

std::ifstream infile (file_name.c_str());

int row = -1; 
std::string col;
std::string uid;


while (infile >> row >> col >> uid) {

    ### operations on row, col and uid ####

}

3 个答案:

答案 0 :(得分:2)

很难直接做到这一点。这是因为您需要使用格式化(operator>>)和非格式化(std::getline)输入例程的组合。

您想使用operator>>来读取id字段(并正确解析整数);但是,您还希望使用函数std::getline(),使用第三个参数'\t'来读取制表符分隔字段(注意:字段终止符默认为'\n'行分隔值)。

通常,您不希望将operator>>std::getline()的用法混合在一起,因为它们处理空格的方式。

所以最好的解决方案是编写自己的输入操作符并以受控方式显式处理该额外空间。

怎么做:

我会创建一个代表该行的类。

struct Line
{
    int          id;
    std::string  col;
    std::string  uid;

    void swap(Line& other) noexcept {
        using std::swap;
        swap(id, other.id);
        swap(col, other.col);
        swap(uid, other.uid);
    }
    friend std::istream& operator>>(std::istream& in, Line& data);
};

然后你需要在输入操作符中定义读取该行。

std::istream& operator>>(std::istream& in, Line& data)
{
    Line   tmp;
    if (// 1 Read the id. Then disicard leading white space before second field.
        (linestream >> tmp.id >> std::ws) && 
        // 2 Read the second field (which is terminated by tab)
        (std::getline(tmp.col, linestream, '\t') &&
        // 3 Read the third field  (which is terminated by newline)
        (std::getline(tmp.uid, linestream)
        // I am being lazy on 3 you may want to be more specific.
       )
    {
        // We have correctly read all the data we need from
        // the line so set the data object from the tmp value.
        data.swap(tmp);
    }
    return in;
}

现在它可以轻松使用。

Line line;
while (infile >> line) {

    ### operations on row, col and uid ####

}

答案 1 :(得分:0)

一个可能如下:

#include <iostream>
#include <vector>
#include <fstream>
#include <iterator>
#include <sstream>

using namespace std;

// take from http://stackoverflow.com/a/236803/248823
void split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss;
    ss.str(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
}

int main() {
    std::ifstream infile ("./data.asc");

    std::string line;



    while (std::getline(infile, line))
    {
        vector<string> row_values;

        split(line, '\t', row_values);

        for (auto v: row_values)
            cout << v << ',' ;

        cout << endl;
     }

    cout << "hello " << endl;
    return 0;
}

结果:

1,hellow world,uid_1,
2,good morning,uid_2,

注意尾随的逗号。不确定你要对文件中的值做什么,所以我刚才做的很简单。

答案 2 :(得分:0)

您也可以使用向量并按以下方式存储内容

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
 

 
std::vector<std::string> StringToVector(std::string, 
        char separator);
 
// ----- END OF PROBLEM FUNCTION PROTOTYPE -----
 
int main()
{
    std::ofstream writeToFile;
    std::ifstream readFromFile;
    std::string txtToWrite = "";
    std::string txtFromFile = "";
       
    // Open the file for reading
    readFromFile.open("test.txt", std::ios_base::in);
    
    if(readFromFile.is_open()){
        
        // Read text from file
        while(readFromFile.good()){
            getline(readFromFile, txtFromFile);
        
           
            std::vector<std::string> vect = 
                    StringToVector(txtFromFile, '\t');
            
          for(int i=0;i<vect.size();i++){
              std::cout<<vect[i]<<"\t";
            }
          std::cout<<"\n\n";
        }   
        readFromFile.close();
    }
    
    return 0;
}
 
// ----- PROBLEM FUNCTION -----
 
std::vector<std::string> StringToVector(std::string theString, 
        char separator){
 
    // Create a vector
    std::vector<std::string> vecsWords;
    
    // A stringstream object receives strings separated
    // by a space and then spits them out 1 by 1
    std::stringstream ss(theString);
    
    // Will temporarily hold each word in the string
    std::string sIndivStr;
    
    // While there are more words to extract keep
    // executing
    // getline takes strings from a stream of words stored
    // in the stream and each time it finds a blanks space
    // it stores the word proceeding the space in sIndivStr
    while(getline(ss, sIndivStr, separator)){
        
        // Put the string into a vector
        vecsWords.push_back(sIndivStr);
    }
    
    return vecsWords;
}