如何在 C++ 中读取带有逗号分隔值的流? [英] How to read a stream with comma separated values in C++?

查看:36
本文介绍了如何在 C++ 中读取带有逗号分隔值的流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想强调以下一个基本问题:

I would like to emphasize on a fundamental question below:

假设您有一个 CSV 文件并用输入标题填充单元格

Assume you have a CSV file and fill cells with Input Headers

代码应该从 .csv 文件中读取它并将结果写入 .csv 文件.还可以编码输出案例总数,加上案例的平均值.这是一个采取的样本形式 SO,我想看看如何有效地采用它来完成这个基本示例.

The code should read this from .csv file and write the results into .csv file. It is nice to also code output total number of cases, plus average of cases. Here is a taken sample form SO and I would like to see how this can be efficiently adopted to complete this basic example.

   void create() 
{ 
    // file pointer 
    fstream fout; 

    // opens an existing csv file or creates a new file. 
    fout.open("reportcard.csv", ios::out | ios::app); 

    cout << "Enter the details of 5 students:"
        << " roll name maths phy chem bio"; 
    << endl; 

    int i, roll, phy, chem, math, bio; 
    string name; 

    // Read the input 
    for (i = 0; i < 5; i++) { 

        cin >> roll 
            >> name 
            >> math 
            >> phy 
            >> chem 
            >> bio; 

        // Insert the data to file 
        fout << roll << ", "
            << name << ", "
            << math << ", "
            << phy << ", "
            << chem << ", "
            << bio 
            << "\n"; 
    } 
} 

另外,读取特定记录

void read_record() 
{ 

    // File pointer 
    fstream fin; 

    // Open an existing file 
    fin.open("reportcard.csv", ios::in); 

    // Get the roll number 
    // of which the data is required 
    int rollnum, roll2, count = 0; 
    cout << "Enter the roll number "
        << "of the student to display details: "; 
    cin >> rollnum; 

    // Read the Data from the file 
    // as String Vector 
    vector<string> row; 
    string line, word, temp; 

    while (fin >> temp) { 

        row.clear(); 

        // read an entire row and 
        // store it in a string variable 'line' 
        getline(fin, line); 

        // used for breaking words 
        stringstream s(line); 

        // read every column data of a row and 
        // store it in a string variable, 'word' 
        while (getline(s, word, ', ')) { 

            // add all the column data 
            // of a row to a vector 
            row.push_back(word); 
        } 

        // convert string to integer for comparision 
        roll2 = stoi(row[0]); 

        // Compare the roll number 
        if (roll2 == rollnum) { 

            // Print the found data 
            count = 1; 
            cout << "Details of Roll " << row[0] << " : \n"; 
            cout << "Name: " << row[1] << "\n"; 
            cout << "Maths: " << row[2] << "\n"; 
            cout << "Physics: " << row[3] << "\n"; 
            cout << "Chemistry: " << row[4] << "\n"; 
            cout << "Biology: " << row[5] << "\n"; 
            break; 
        } 
    } 
    if (count == 0) 
        cout << "Record not found\n"; 
} 


  [1]: https://i.stack.imgur.com/q6VfZ.png

推荐答案

自从你之前对这些表现出一些兴趣,并在代码的注释中描述了他们在做什么.

I've mainly concentrated on adding overloads for operator<< and operator>> since you showed some interest in those earlier and describe what they are doing in comments in the code.

由于您要混合来自逗号分隔的流和其他流的输入和输出,因此我添加了一个用于 CSV 流的适配器以及用于与用户进行流传输的重载.

Since you are mixing input and output from streams that are comma separated and other streams I've added an adapter for CSV streaming as well as overloads for streaming to/from a user.

首先,创建一个class,将所有属于一起的数据保存在一个数据记录中.我在这里做了一个简单的struct,它是一个class,默认情况下可以public访问其成员.

First, create a class to keep all data that belongs together in one data record. I've made it a simple struct here, which is a class with public access to its members per default.

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

// your student record
struct student {
    std::string name; // It's usually good to have larger types first so name goes first
    int roll;
    int math;
    int phy;
    int chem;
    int bio;
};

// read a student from an istream (like std::cin) - whitespace separated
std::istream& operator>>(std::istream& is, student& s) {
    return is >> s.roll >> s.name >> s.math >> s.phy >> s.chem >> s.bio;
}

// write a student to an ostream (like std::cout)
std::ostream& operator<<(std::ostream& os, const student& s) {
    return os << "Details of Roll " << s.roll << ":\n"
              << "Name: " << s.name << '\n'
              << "Maths: " << s.math << '\n'
              << "Physics: " << s.phy << '\n'
              << "Chemistry: " << s.chem << '\n'
              << "Biology: " << s.bio << '\n';
}
//--------------------------------------------------------------------------------------
// An adapter for comma separated streaming
struct CSVStudent {
    CSVStudent(student& s) : stud(s) {}
    CSVStudent(const CSVStudent&) = delete;

    // The CSVStudent holds a reference to a "student"
    student& stud;
};

// read a record from an istream - comma separated
std::istream& operator>>(std::istream& is, CSVStudent& csvstud) {
    std::string line;

    student& s = csvstud.stud; // an alias to the student to have to type less

    if(std::getline(is, line)) { // read a complete line
        // put the line in an istringstream for extraction:
        std::istringstream ss(line);

        char delim; // a dummy for reading commas

        // Extract the comma separated values. "delim" is not checked so it could be
        // any char breaking up the int:s.
        //
        // The below does things in the following order:
        // 1.  "ss >> s.roll >> delim"
        //     This extracts roll and a comma and returns
        //     a reference to ss, which is used in 2.
        // 2.  std::getline(ss, s.name, ',')
        //     Extracts a string until a comma is encountered.
        // 3.  Normal extraction for the rest of the int:s with the
        //     dummy variable "delim" where the commas are supposed to be.

        if(not(std::getline(ss >> s.roll >> delim, s.name, ',') >> s.math >> delim >>
               s.phy >> delim >> s.chem >> delim >> s.bio)) {
            // If we get here, the extraction from the istringstream failed, so set
            // the failstate on the istream too. Note the "not" on the line above.
            is.setstate(std::ios::failbit);
        }
    }
    return is;
}

// write a record to an ostream - comma separated
std::ostream& operator<<(std::ostream& os, const CSVStudent& csvstud) {
    const student& s = csvstud.stud;
    os << s.roll << ',' << s.name << ',' << s.math << ',' << s.phy << ',' << s.chem
       << ',' << s.bio << '\n';
    return os;
}
//--------------------------------------------------------------------------------------
// get all students in the file as a std::vector<student>
std::vector<student> read_student_file(const std::string& filename) {
    std::vector<student> retval;
    std::ifstream fin(filename);
    if(fin) { // file opened successfully
        student stud;
        CSVStudent csvstud{stud}; // holds a reference to stud

        // loop for as long as student records can be read successfully
        while(fin >> csvstud)       // use the csv sdapter
            retval.push_back(stud); // and put the stud in the vector
    }
    return retval;
}
//--------------------------------------------------------------------------------------
void create(const std::string& filename) {
    // open an existing csv file or creates a new file.
    std::ofstream fout(filename, std::ios::out | std::ios::app);
    if(fout) {
        std::cout << "Enter the details of 5 students:"
                     " roll name maths phy chem bio\n";

        // Read the input
        for(int i = 0; i < 5; i++) {
            student stud;
            std::cout << (i + 1) << ": ";
            if(std::cin >> stud) {
                // Insert the data to file if one was entered successfully
                fout << CSVStudent(stud); // uses the adapters operator<<
            } else {
                std::cerr << "You failed to enter data for student " << (i + 1) << '\n';
                break;
            }
        }
    }
}
//--------------------------------------------------------------------------------------
int main() {
    std::string filename = "reportcard.csv";

    std::vector<student> students = read_student_file(filename);

    std::cout << "There are " << students.size() << " students in the file.\n";
    if(not students.empty()) {
        // show the last record if there are any records in the file
        std::cout << "Record " << students.size() << " is:\n\n";
        std::cout << students.back() << '\n';
    }

    // create 5 new records
    create(filename);
}

如果 reportcard.csv 包含这个:

1,Ted,1,2,3,4
2,Foo,2,3,4,5
3,Bar,3,4,5,6
4,Baz,4,5,6,7
5,Bork,5,6,7,8

程序应该像这样启动:

There are 5 students in the file.
Record 5 is:

Details of Roll 5:
Name: Bork
Maths: 5
Physics: 6
Chemistry: 7
Biology: 8

Enter the details of 5 students: roll name maths phy chem bio
1: <and here is where you're supposed to enter the first of 5 new students>

这篇关于如何在 C++ 中读取带有逗号分隔值的流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆