C++ 在csv中读取Getline非常奇怪
我正在尝试使用get行读取csv,以提取三个用逗号分隔的变量。姓名、课程和年级 我读的第一行很好,但它加入了奇怪的换行符,并将格式发送到集群中 这是我的密码:C++ 在csv中读取Getline非常奇怪,c++,file,csv,getline,C++,File,Csv,Getline,我正在尝试使用get行读取csv,以提取三个用逗号分隔的变量。姓名、课程和年级 我读的第一行很好,但它加入了奇怪的换行符,并将格式发送到集群中 这是我的密码: #include "header.h" string student::GetCourse() { return course; } string student::GetName() { return name; } string student::GetGrade() { return grade; }
#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;
}
}
任何想法,我都很难读懂这个文件。好了,开始吧
如果文件!=\n比较是荒谬的。它不会做你认为它会做的事。
等级后的分隔符不是“,”,而是“\n”。
虽然file.eof不正确。只有在EOF已经发生后才进行检查。您应该检查getline的返回值
也
通常在C++中,你做STD::IFFStudio文件。您不需要单独调用open。
您不需要将std::string初始化为。这是自动发生的。即使你必须这么做,你也应该写
std::字符串a=,b=,c=
如果您使用std::stringa,b,c=something,那么只有c被初始化为something
第一:您没有检查输入是否在任何地方成功。见鬼,你甚至不检查文件是否可以打开:
int main () { // it's int main()!
ifstream file("short.txt");
if(!file.good()) {
std::cerr << "couldn't open \"short.txt\"\n";
return 1;
}
vector <student> StudentList;
for(;;) {
// ...
}
if( !file.eof() ) {
std::cerr << "error reading before eof!\n";
return 2;
}
// ...
}
然后通过字符串流读取这些行。我会将代码逐行读取放到它自己的函数中:
std::istream& read_line(std::istream& is, StudentList& list)
{
std::string value1, value2, value3;
std::getline(is, value1, ',');
std::getline(is, value2, ',');
std::getline(is, value3, ',');
if(is)
StudentList.push_back(...);
}
// ...
for(;;) {
std::string line;
std::getline(file, line);
if(!file) break;
std::istringstream iss(line);
read_line(iss, StudentList);
if(!iss) break;
}
// ...
嗯 在调用中将分隔符设置为“,”
getline(file, tempname, ',');
你不是一次读一整行。“\n”是默认分隔符,通过使用默认值,您将获得整行,而不仅仅是其中的一部分
我建议使用默认分隔符来读取整行内容,然后使用“,”作为分隔符并使用if!file.eof
确定您何时读完该文件。您已经得到了许多答案。虽然他们的建议肯定比你现在所做的有所改进,但我的处理方式与他们的建议有所不同 现在,您的学生类基本上在尽最大努力模仿哑数据,即只是一个简单的结构,但语法更难看-您为每个成员使用一个get/set对,但他们没有添加任何内容。学生类本身就像一个简单的结构一样愚蠢。学生的所有逻辑仍然在学生课堂之外 为了使其有用,student类应该包含相当数量的相关逻辑,例如如何从流中读入学生,或者如何在不同的流中显示学生:
class student {
std::string name, course, grade;
public:
bool operator<(student const &other) const {
return name < other.name;
}
friend std::ostream &operator<<(std::ostream &os, student const &st) {
return os << st.name << " " << st.course << " " << st.grade;
}
friend std::istream &operator>>(std::istream &is, student &st) {
std::string temp;
is >> temp;
std::istringstream t(temp);
std::getline(t, st.name, ',');
std::getline(t, st.course, ',');
std::getline(t, st.grade);
return is;
}
};
这使主要问题变得相当简单:
int main() {
std::ifstream in("short.txt");
std::vector<student> students;
std::copy(std::istream_iterator<student>(in),
std::istream_itertor<student>(),
std::back_inserter(students));
std::sort(students.begin(), students.end());
std::copy(students.begin(), students.end(),
std::ostream_iterator<student>(std::cout, "\n"));
return 0;
}
特别要注意的是,main只将整个学生作为一个逻辑实体来处理——它从不在学生对象内部查看其组成部分。一些评论:
不要写你自己的那一类。
STL有自己的内置排序算法。
您只需指定对象之间的关系:
bool operator<(student const& lhs,student const& rhs)
{
return lhs.GetName() < rhs.GetName();
}
// Now a sort is:
std::sort(list.begin(),list.end());
不要使用幻数:
你是真的忽略了8000个字符,还是只是想删除一行
file.ignore(8196,'\n');
你有两个选择:
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')
使用stringstream将线拆分为多个部分
我不知道你在这里想干什么
if (file != "\n")
{ getline(file, tempname, ',');
getline(file, tempcourse, ',');
getline(file, tempgrade, ',');
}
我认为如果我们将其与上面的循环结合起来,阅读起来会更容易:
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
}
}
当机会出现时,用标准算法替换循环
此打印循环可由std::copy替换
for (int i = 0; i < StudentList.size(); i++)
{ cout << StudentList[i].GetName() << " "
<< StudentList[i].GetCourse() << " "
<< StudentList[i].GetGrade() << endl;
}
在这里,您将文件与“C字符串”进行比较。我不确定编译器是如何编译的。
有几种选择浮现在脑海中,但事实上它并不明显,这可能是一个bug的来源。还要注意,这不是比较两个字符串的方式,除非其中一个是std::string
我认为编译器会将文件转换为指针,并将其与C字符串进行比较,因为这也只是一个指针。您可能认为这有点奇怪,但有一个操作符可以将文件转换为空*。指针不指向任何有意义的,但它是空的或不空的,可以与char *指针进行比较,从而得到一个真值,因为它不等于字符串\n。< /p>编辑好,以正确地格式化所有代码,但我怀疑任何人都会读取它:为什么在C++中这样做?你应该使用其他任何东西:perl、python、ruby、tcl……Jon,我猜这是一个家庭作业问题。我更喜欢他的答案。它更详细:这不是一个好主意“whilefile.good”,因为它测试得太早或太迟。你应该测试行动的结果。”因此,如果它失败,则永远不会进入循环。通过良好的测试,您需要在阅读后再次测试。读取文件的经典反模式。在初始化字符串部分,您可能想执行以下操作?std::字符串a=b=c=;这是行不通的,因为它假设b和c已经定义好了。您必须这样做:std::stringa,b,c;a=b=c=;但这不再是初始化,这是分配。@Martin York,我知道我甚至在回答中提到了它:。这是关于初始化的。@Martin:我修正了一些打字错误,
我希望没问题。我同意你所说的每一点。@sbi:总是愿意接受帮助。谢谢你的更正。
if (file != "\n")
{ getline(file, tempname, ',');
getline(file, tempcourse, ',');
getline(file, tempgrade, ',');
}
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
}
}
for (int i = 0; i < StudentList.size(); i++)
{ cout << StudentList[i].GetName() << " "
<< StudentList[i].GetCourse() << " "
<< StudentList[i].GetGrade() << endl;
}
std::ostream& operator<<(std::ostream& str,student const& data)
{
str << data.getName() << " "
<< data.getCourse() << " "
<< data.getGrade() << " "; // No newline here.
return str;
}
std::copy(StudentList.begin(),StudentList.end(),
std::ostream_iterator<student>(std::cout,"\n")
);
if (file != "\n")