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

6

我需要使用一些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 ####

}

1
也许使用std::getline更合适?它会读取所有字符,然后将制表符作为分隔符? - BleuGamer
3个回答

4
以下是一种可能的方式:

其中一种方式如下:

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

using namespace std;

// take from https://dev59.com/k3VC5IYBdhLWcg3wnCj6#236803
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

直接这样做很难。这是因为您需要使用格式化(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 ####

}

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接