C ++在循环内使用getline()读取CSV文件

时间:2019-06-30 15:20:21

标签: c++ getline

我正在尝试读取一个CSV文件,该文件包含3人/患者的行,其中col 1是userid,col 2是fname,col 3是lname,col 4是保险,col 5是看起来是的版本像下面这样。

编辑:抱歉,我只是在此处复制/粘贴了CSV电子表格,因此以前没有显示逗号。它看起来不像下面吗?下面的John还指出,该版本之后没有逗号,这似乎可以解决该问题!非常感谢约翰! (试图弄清楚我如何接受您的回答:))

nm92,Nate,Matthews,Aetna,1
sc91,Steve,Combs,Cigna,2
ml94,Morgan,Lands,BCBS,3

我正在尝试在循环内使用getline()读取所有内容,并且在第一次迭代中工作正常,但是getline()似乎导致它在下一次迭代中跳过了一个值。知道我该如何解决吗?

我也不确定为什么输出如下图所示,因为我看不到代码中有w /“ sc91”和“ ml94”的行。这就是当前代码的输出。

userid is: nm92
fname is: Nate
lname is: Matthews
insurance is: Aetna
version is: 1
sc91
userid is: Steve
fname is: Combs
lname is: Cigna
insurance is: 2
ml94
version is: Morgan
userid is: Lands
fname is: BCBS
lname is: 3

insurance is:
version is:

我已经对getline()和>>流运算符之间的差异进行了大量研究,但是大多数getline()材料似乎都是围绕从cin获取输入而不是从像这样的文件中读取,所以我在想w / getline()上正在发生什么,以及它如何读取我不理解的文件。不幸的是,当我尝试>>运算符时,这迫使我使用strtok()函数,并且我在使用c字符串并将其分配给C ++字符串数组方面工作很多。

#include <iostream>
#include <string>                               // for strings
#include <cstring>                              // for strtok()
#include <fstream>                              // for file streams

using namespace std;

struct enrollee
{
    string userid = "";
    string fname = "";
    string lname = "";
    string insurance = "";
    string version = "";
};

int main()
{
    const int ENROLL_SIZE = 1000;               // used const instead of #define since the performance diff is negligible,
    const int numCols = 5;                    // while const allows for greater utility/debugging bc it is known to the compiler ,
                                                // while #define is a preprocessor directive
    ifstream inputFile;                         // create input file stream for reading only
    struct enrollee enrollArray[ENROLL_SIZE];   // array of structs to store each enrollee and their respective data
    int arrayPos = 0;

    // open the input file to read
    inputFile.open("input.csv");
    // read the file until we reach the end
    while(!inputFile.eof())
    {
        //string inputBuffer;                         // buffer to store input, which will hold an entire excel row w/ cells delimited by commas
                                                    // must be a c string since strtok() only takes c string as input
        string tokensArray[numCols];
        string userid = "";
        string fname = "";
        string lname = "";
        string insurance = "";
        string sversion = "";
        //int version = -1;

        //getline(inputFile,inputBuffer,',');
        //cout << inputBuffer << endl;

        getline(inputFile,userid,',');
        getline(inputFile,fname,',');
        getline(inputFile,lname,',');
        getline(inputFile,insurance,',');
        getline(inputFile,sversion,',');

        enrollArray[0].userid = userid;
        enrollArray[0].fname = fname;
        enrollArray[0].lname = lname;
        enrollArray[0].insurance = insurance;
        enrollArray[0].version = sversion;

        cout << "userid is: " << enrollArray[0].userid << endl;
        cout << "fname is: " << enrollArray[0].fname << endl;
        cout << "lname is: " << enrollArray[0].lname << endl;
        cout << "insurance is: " << enrollArray[0].insurance << endl;
        cout << "version is: " << enrollArray[0].version << endl;
    }
}

3 个答案:

答案 0 :(得分:1)

这只是一个主意,但可以为您提供帮助。这是我正在从事的一个项目的代码:

std::vector<std::string> ARDatabase::split(const std::string& line, char delimiter)
{
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(line);
    while (std::getline(tokenStream, token, delimiter))
    {
        tokens.push_back(token);
    }
    return tokens;
}

void ARDatabase::read_csv_map(std::string root_csv_map)
{
    qDebug() << "Starting to read the people database...";
    std::ifstream file(root_csv_map);
    std::string str;
    while (std::getline(file, str))
    {
        std::vector<std::string> tokens = split(str, ' ');
        std::vector<std::string> splitnames = split(tokens.at(1), '_');

        std::string name_w_spaces;
        for(auto i: splitnames) name_w_spaces = name_w_spaces + i + " ";

        people_names.insert(std::make_pair(stoi(tokens.at(0)), name_w_spaces));
        people_images.insert(std::make_pair(stoi(tokens.at(0)), std::string("database/images/" + tokens.at(2))));

    }
}

您可能希望使用其他更适合您的情况的容器来代替std :: vector。最后一个示例针对我的案例的输入格式。您可以轻松地对其进行修改,以使其适应您的代码。

答案 1 :(得分:1)

您的问题是每行最后一个数据项后面没有逗号,所以

 getline(inputFile,sversion,',');

是不正确的,因为它会读取下一个逗号,该逗号实际上位于下一位患者的用户ID之后的下一行。这说明了您看到的输出,在该输出中,下一个专利的用户ID在哪里获得了该版本的输出。

要解决此问题,只需将上面的代码替换为

 getline(inputFile,sversion);

将根据需要读取到行尾。

答案 2 :(得分:1)

关于您的功能。如果查看源文件的结构,则将看到它包含5个字符串,以“,”分隔。因此是典型的CSV文件。

调用std::getline将读取包含5个字符串的完整行。在您的代码中,您尝试为每个单个字符串调用std::getline,后跟一个逗号。最后一个字符串后不存在Commaa。这是行不通的。您还应该使用getline获取完整行。

您需要阅读整行,然后将其标记化。

我将向您展示如何使用std::sregex_token_iterator进行操作的示例。那很简单。此外,我们将覆盖插入程序和Extracot运算符。这样一来,您就可以轻松读写Enrollee e{}; std::cout << e;

之类的“注册人”数据

此外,我使用C ++算法。这使生活非常轻松。输入和输出主要是一线的。

请参阅:

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <regex>


struct Enrollee
{
    // Data
    std::string userid{};
    std::string fname{};
    std::string lname{};
    std::string insurance{};
    std::string version{};

    // Overload Extractor Operator to read data from somewhere
    friend std::istream& operator >> (std::istream &is, Enrollee& e) {
        std::vector<std::string> wordsInLine{};       // Here we will store all words that we read in onle line;
        std::string wholeLine;                        // Temporary storage for the complete line that we will get by getline
        std::regex separator("[ \\;\\,]"); ;          // Separator for a CSV file
        std::getline(is, wholeLine);                  // Read one complete line and split it into parts
        std::copy(std::sregex_token_iterator(wholeLine.begin(), wholeLine.end(), separator, -1), std::sregex_token_iterator(), std::back_inserter(wordsInLine));
        // If we have read all expted strings, then store them in our struct
        if (wordsInLine.size() == 5) {
            e.userid = wordsInLine[0];
            e.fname = wordsInLine[1];
            e.lname = wordsInLine[2];
            e.insurance = wordsInLine[3];
            e.version = wordsInLine[4];
        }
        return is;
    }

    // Overload Inserter operator. Insert data into output stream
    friend std::ostream& operator << (std::ostream& os, const Enrollee& e) {
        return os << "userid is:    " << e.userid << "\nfname is:     " << e.fname << "\nlname is:     " << e.lname << "\ninsurance is: " << e.insurance << "\nversion is:   " << e.version << '\n';
    }
};


int main()
{
    // Her we will store all Enrollee data in a dynamic growing vector
    std::vector<Enrollee> enrollmentData{};

    // Define inputFileStream and open the csv
    std::ifstream inputFileStream("r:\\input.csv");

    // If we could open the file
    if (inputFileStream) {

        // Then read all csv data
        std::copy(std::istream_iterator<Enrollee>(inputFileStream), std::istream_iterator<Enrollee>(), std::back_inserter(enrollmentData));

        // For Debug Purposes: Print all data to cout
        std::copy(enrollmentData.begin(), enrollmentData.end(), std::ostream_iterator<Enrollee>(std::cout, "\n"));
    }
    else {
        std::cerr << "Could not open file 'input.csv'\n";
    }
}

这将读取包含以下内容的输入文件“ input.csv”

nm92,Nate,Matthews,Aetna,1
sc91,Steve,Combs,Cigna,2
ml94,Morgan,Lands,BCBS,3

并显示为输出:

userid is:    nm92
fname is:     Nate
lname is:     Matthews
insurance is: Aetna
version is:   1

userid is:    sc91
fname is:     Steve
lname is:     Combs
insurance is: Cigna
version is:   2

userid is:    ml94
fname is:     Morgan
lname is:     Lands
insurance is: BCBS
version is:   3
相关问题