Getline在csv读取非常奇怪

0 c++ csv file getline

我正在尝试使用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)

任何想法,我在阅读这个文件真的很难.

hrn*_*rnt 7

嗯,这里

  • if (file != "\n")比较是荒谬的.它没有做你认为它做的事情.
  • 等级后你的分隔符不是',',它是'\n'.
  • while (!file.eof())是不正确的.只有在EOF发生后才检查它.您应该检查你的返回值getline(),而不是

  • 通常用C++做std::ifstream file("short.txt");.您无需open()单独呼叫.
  • 您不需要初始化std::string为"".这会自动发生.即使你必须这样做,那么你应该写

    std::string a = "", b = "", c = "";.

    如果你这样做,std::string a, b, c = "something"那么只有c被初始化为某种东西.


Mar*_*ork 5

一些评论:

不要写自己的排序。

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 (!file.eof())

这是读取文件的标准反模式。
问题是考试要么太早,要么晚两点。如果你还没有读过任何东西,那么现在已经两点了,因为什么也没有发生。如果您已经阅读了某些内容,那么已经太晚了,因为您已经对所阅读的项目进行了处理(但失败了)。

最好的方法是将读取放入 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”)。