我正在尝试使用get行读取csv以提取由逗号分隔的三个变量.姓名,课程和成绩.
我在第一行阅读很好,但它放入了奇怪的新换行符并将格式发送到群集中.
这是我的代码:
#include "header.h"
string student::GetCourse() {
return course;
}
string student::GetName() {
return name;
}
string student::GetGrade() {
return grade;
}
void student::setname(string n) {
name = n;
}
void student::setCourse(string c) {
course = c;
}
void student::setGrade(string g) {
grade = g;
}
void sort (vector <student> &List) {
student temp;
int first = 1;
int vectorLength = List.size() - 1;
for (int i = vectorLength; i > 0; i--) {
first = i;
for (int j = 0; j < i; j++) {
if (List[j].GetName() > List[first].GetName())
first = j;
}
temp = List[first];
List[first] = List[i];
List[i] = temp;
}
}
void main () {
ifstream file;
vector <student> StudentList;
file.open("short.txt");
while (!file.eof()) {
file.ignore(8196,'\n');
string tempname, tempgrade, tempcourse = "";
if (file != "\n") {
getline(file, tempname, ',');
getline(file, tempcourse, ',');
getline(file, tempgrade, ',');
}
student s;
s.setCourse(tempcourse);
s.setname (tempname);
s.setGrade (tempgrade);
StudentList.push_back(s);
}
//sort (StudentList);
for (int i = 0; i < StudentList.size(); i++) {
cout << StudentList[i].GetName() << " " << StudentList[i].GetCourse() << " " << StudentList[i].GetGrade() << endl;
}
}
Run Code Online (Sandbox Code Playgroud)
任何想法,我在阅读这个文件真的很难.
嗯,这里
if (file != "\n")比较是荒谬的.它没有做你认为它做的事情.',',它是'\n'.while (!file.eof())是不正确的.只有在EOF发生后才检查它.您应该检查你的返回值getline(),而不是也
std::ifstream file("short.txt");.您无需open()单独呼叫.您不需要初始化std::string为"".这会自动发生.即使你必须这样做,那么你应该写
std::string a = "", b = "", c = "";.
如果你这样做,std::string a, b, c = "something"那么只有c被初始化为某种东西.
一些评论:
STL 有自己内置的排序算法。
您所要做的就是指定对象之间的关系:
bool operator<(student const& lhs,student const& rhs)
{
return lhs.GetName() < rhs.GetName();
}
// Now a sort is:
std::sort(list.begin(),list.end());
Run Code Online (Sandbox Code Playgroud)
这是读取文件的标准反模式。
问题是考试要么太早,要么晚两点。如果你还没有读过任何东西,那么现在已经两点了,因为什么也没有发生。如果您已经阅读了某些内容,那么已经太晚了,因为您已经对所阅读的项目进行了处理(但失败了)。
最好的方法是将读取放入 while 循环中。这是因为读取的结果返回对流的引用。这可以自动转换为可以在布尔上下文中使用的对象(转换测试以查看流是否有问题)。因此,读取失败将使流处于一种状态,导致其在布尔上下文中转换为相当于 false 的状态。
std::string line;
while(std::getline(file,line))
{
// loop only entered if getline() worked.
// Thus we know that we have a good value in line.
// use line
}
Run Code Online (Sandbox Code Playgroud)
您真的忽略了 8000 个字符还是只是想删除一行?
file.ignore(8196,'\n');
Run Code Online (Sandbox Code Playgroud)
您有两种选择:
std::string ignoreLine;
std::getline(file,ignoreLine);
// Dont use a magic number but use a number that is guranteed not to fail.
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
Run Code Online (Sandbox Code Playgroud)
编程最重要的是编写可维护的代码。
使用这种初始化(相对普遍地)被谴责为懒惰。将每个声明放在单独的行上。它使代码更易于阅读。
string tempname, tempgrade, tempcourse = "";
// Like this:
std::string tempname;
std::string tempgrade;
std::string tempcourse;
Run Code Online (Sandbox Code Playgroud)
我不确定你在这里尝试什么?
if (file != "\n")
{ getline(file, tempname, ',');
getline(file, tempcourse, ',');
getline(file, tempgrade, ',');
}
Run Code Online (Sandbox Code Playgroud)
我认为如果我们将它与上面的循环结合起来会更容易阅读:
std::string line;
while(std::getline(file,line))
{
std::stringstream linestr(line);
if (getline(linestr, tempname, ',') &&
getline(linestr, tempcourse, ',') &&
getline(linestr, tempgrade, ',')
)
{
// Here we have read a line.
// And successfully retrieved three comma separated values from the line
}
}
Run Code Online (Sandbox Code Playgroud)
这个打印循环可以用 std::copy() 代替
for (int i = 0; i < StudentList.size(); i++)
{ cout << StudentList[i].GetName() << " "
<< StudentList[i].GetCourse() << " "
<< StudentList[i].GetGrade() << endl;
}
Run Code Online (Sandbox Code Playgroud)
您需要做的就是为您的类定义一个输出运算符。
std::ostream& operator<<(std::ostream& str,student const& data)
{
str << data.getName() << " "
<< data.getCourse() << " "
<< data.getGrade() << " "; // No newline here.
return str;
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以将向量复制到 std::cout
std::copy(StudentList.begin(),StudentList.end(),
std::ostream_iterator<student>(std::cout,"\n")
);
Run Code Online (Sandbox Code Playgroud)
我看到的主要错误是这一行:
if (file != "\n")
Run Code Online (Sandbox Code Playgroud)
在这里,您将文件与“C 字符串”进行比较。我不确定编译器如何编译它。
我想到了几个选项,但事实上它并不明显,这使得它很可能是错误的来源。另请注意,这不是比较两个字符串的方式(除非其中一个是 std::string)。
我认为编译器会将文件转换为指针并将其与“C-String”进行比较(因为这也只是一个指针)。您可能认为这有点奇怪,但有一个运算符可以将文件转换为 void*。该指针不指向任何有意义的东西,但要么是 NULL,要么不是 NULL,并且可以与 char* 指针进行比较,从而得到 true(因为它永远不等于字符串“\n”)。