C++ 如何在C+中读取带有逗号分隔值的流+;?
我想强调以下一个基本问题: 假设您有一个CSV文件,并用输入标题填充单元格 代码应该从.csv文件中读取此内容,并将结果写入.csv文件。还可以编写输出案例总数加上案例平均数的代码。这是一个样本表格,我想看看如何有效地采用它来完成这个基本示例C++ 如何在C+中读取带有逗号分隔值的流+;?,c++,csv,stream,C++,Csv,Stream,我想强调以下一个基本问题: 假设您有一个CSV文件,并用输入标题填充单元格 代码应该从.csv文件中读取此内容,并将结果写入.csv文件。还可以编写输出案例总数加上案例平均数的代码。这是一个样本表格,我想看看如何有效地采用它来完成这个基本示例 void create() { // file pointer fstream fout; // opens an existing csv file or creates a new file. fout
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 create()
{
//文件指针
fstream-fout;
//打开现有csv文件或创建新文件。
fout.open(“reportcard.csv”,ios::out | ios::app);
姓名
>>数学
>>物理层
>>化学
>>生物;
//将数据插入到文件中
fout我主要集中在为操作符
添加重载,因为您在前面对这些重载表示了一些兴趣,并在代码的注释中描述了它们在做什么
由于您混合了逗号分隔的流和其他流的输入和输出,因此我添加了一个用于CSV
流的适配器,以及用于向/从用户流的重载
首先,创建一个类
,将所有属于同一个数据记录的数据保存在一起。我在这里把它做成了一个简单的结构
,它是一个类
,默认情况下可以访问其成员
#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);
}
程序应按如下方式启动:
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>
文件中有5名学生。
记录5是:
第5卷的详细信息:
姓名:博克
数学:5
物理:6
化学:7
生物学:8
输入5名学生的详细信息:卷名数学物理化学生物
1:你忘了带标签。这看起来不是很简单(如中所示)而且你也很难理解你所拥有的问题。上面提到的代码中的示例数据似乎与代码无关。代码涉及移动平均值等。添加了标记C++。此外,还添加了一个语句,平均值和案例总数也在愿望列表中。RE有很多例子,问题是如何导航,修改它们,以便对新用户C++进行最基本的练习,就像我在这个问题上提出的那样。你能为这个提议做出贡献吗?恐怕你误解了这个站点应该如何工作。人们通常不会为你做实现/适应。试着自己做,如果你遇到了问题,就提出一个你需要帮助的问题。你有简单的逗号分隔的数据,或者有一个奇特的CSV格式,里面有引号和逗号之类的东西吗?现在更好了,虽然它不是一个。如果没有人能比我更好,我会回答的。:-)一个更好的方法是有一个简单的wrapper类(CVSStudent),它只保存对学生的引用,但当序列化器/反序列化器像CVS文件一样读/写时,而普通学生以人类可读的形式进行流式处理:`std::cin>>CVSStudent{studentObject};std::cout@MartinYork是的,我同意添加一层适配器会使它更通用,并保持它更干净。我可能会再补充一点。@Mohammad将关注点分离是很好的。通过使学生
简单,并且只能够从任何ostream/istream
添加基本的流媒体,就很容易添加支持端口类、适配器,以其他特定方式执行流式传输,如csv
等@Mohammad您需要在适用的地方添加验证器,并根据您认为合适的内容拒绝或接受值。要删除值,您只需从std::vector
中删除它,然后将向量中的所有学生写入fil即可e来覆盖您以前拥有的内容。可以通过多种方式完成。如果roll
被认为是唯一的数字,您可以使用std::map studentmap;
将roll
作为键,将student
作为值来创建一个student
学生地图。然后可以使用student&stud=stude>来获得某个学生ntmap.at(roll);
或者您可以保留向量和std::在其中查找学生。无限的可能性。:-)
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>