stringstream在多次调用中不会重置。

huangapple go评论78阅读模式
英文:

stringstream does not reset across several calls

问题

我尝试从文件中加载输入,表示学生。每个学生都有姓名和分数列表,如下所示:

Name John Wayne
Scores 100 90 80 100 0

Name Bob Dwight
Scores 0 0 10 100

Name Dummy Student
Scores 0 0

我通过以下方式使用类结构来读取这些信息。一个课堂对象维护了所有学生的列表。

class Student
{
    string first_name;
    string last_name;
    vector<int> quizzes;

public:
    void read(istream & in){
        string line;

        // 名字初始化
        getline(in, line);
        stringstream namereader(line);

        string word;
        namereader >> word; // 跳过 "Name"
        namereader >> word;
        first_name = word; // 行中的第二个词是名字
        namereader >> word;
        last_name = word; // 行中的第三个词是姓
        
        // 测验分数
        getline(in, line); // 名字后的行包含测验分数
        stringstream quizreader(line);
        quizreader >> word; // 跳过 "Quiz"
        int quizgrade;
        while(quizreader >> quizgrade){ // 读取测验分数并插入
            quizzes.push_back(quizgrade);
        }

        // 清空字符串流 quizreader.str(""), quizreader.clear() 不起作用

        // 每个学生之间有空行
        getline(in, line);
    }
    
    void print(ostream & out) const{
        out << "Name    " << first_name << " " << last_name << endl;
        out << "QZ Ave: " <<  endl;

        for (int i : quizzes){
            cout << i << " ";
        }
        cout << endl;
    }

    friend ostream & operator <<(ostream &out, const Student & student){
        student.print(out);
        return out;
    }

    friend istream & operator >>(istream &in, Student & student){
        student.read(in);
        return in;
    }
};

class Classroom{
    vector<Student> students;
public:
    void print(ostream & out) const{
        for (Student s : students){
            out << s << endl;
        }
    }

    void read(istream & in){
        Student s;
        while (in >> s){
            students.push_back(s);
        }
    }

    friend ostream & operator <<(ostream &out, const Classroom & cl){
        cl.print(out);
        return out;
    }

    friend istream & operator >>(istream &in, Classroom & cl){
        cl.read(in);
        return in;
    }
};

int main(){
    ifstream in("classroom.txt");
    Classroom cl;
    in >> cl;
    cout << cl;
    return 0;
}

当我尝试打印这些信息时,我注意到我的字符串流在 Classroom::read 中的循环调用之间没有重置。

这意味着主函数的输出是:

John Wayne
Scores 100 90 80 100 0

Bob Dwight
Scores 100 90 80 100 0 0 0 10 100

Dummy Student
Scores 100 90 80 100 0 0 0 10 100 0 0

我已经尝试使用.clear().str("")清除所有我的字符串流,但无论我在read()中的哪个位置以及以何种顺序放置它们,它们都不起作用。对我来说奇怪的是,quizreader 保留了之前的所有数字,但 namereader 继续并按预期获取下一个名字。这是否与打开多个字符串流有关?不正确的初始化?我假设所有的输入都是正确的类型,这些问题我将稍后解决。我已经阅读了几乎在这个网站上与这个主题有关的每篇帖子,但似乎找不到可行的解决方案。

英文:

I'm trying to load in input from a file, representing students. Each student has a name and list of scores, like so:

Name John Wayne
Scores 100 90 80 100 0
Name Bob Dwight
Scores 0 0 10 100
Name Dummy Student
Scores 0 0

I am reading this through a class structure like so. A classroom object keeps a list of all students.

class Student
{
string first_name;
string last_name;
vector&lt;int&gt; quizzes;
public:
void read(istream &amp; in){
string line;
// Name initialization
getline(in, line);
stringstream namereader(line);
string word;
namereader &gt;&gt; word; // Go past &quot;Name&quot;
namereader &gt;&gt; word;
first_name = word; // Second word in a line is firstname
namereader &gt;&gt; word;
last_name = word; // Third word in a line is lastname
// Quizzes
getline(in, line); // line after name contains quiz scores
stringstream quizreader(line);
quizreader &gt;&gt; word; // Go past &quot;Quiz&quot;
int quizgrade;
while(quizreader &gt;&gt; quizgrade){ // Read quiz scores and insert
quizzes.insert(quizzes.end(), quizgrade);
}
// Putting quizreader.str(&quot;&quot;), quizreader.clear() does not work
//Empty Line between each student
getline(in, line);
}
void print(ostream &amp; out) const{
out &lt;&lt; &quot;Name    &quot; &lt;&lt; first_name &lt;&lt; &quot; &quot; &lt;&lt; last_name &lt;&lt; endl;
out &lt;&lt; &quot;QZ Ave: &quot; &lt;&lt;  endl;
for (int i : quizzes){
cout &lt;&lt; i &lt;&lt; &quot; &quot;;
}
cout &lt;&lt; endl;
}
friend ostream &amp; operator &lt;&lt;(ostream &amp;out, const Student &amp; student){
student.print(out);
return out;
}
friend istream &amp; operator &gt;&gt;(istream &amp;in, Student &amp; student){
student.read(in);
return in;
}
};

Classroom:

class Classroom{
vector&lt;Student&gt; students;
public:
void print(ostream &amp; out) const{
for (Student s : students){
out &lt;&lt; s &lt;&lt; endl;
}
}
void read(istream &amp; in){
Student s;
while (in &gt;&gt; s){
students.insert(students.end(), s);
}
}
friend ostream &amp; operator &lt;&lt;(ostream &amp;out, const Classroom &amp; cl){
cl.print(out);
return out;
}
friend istream &amp; operator &gt;&gt;(istream &amp;in, Classroom &amp; cl){
cl.read(in);
return in;
}
};

Main function:

int main(){
ifstream in(&quot;classroom.txt&quot;);
Classroom cl;
in &gt;&gt; cl;
cout &lt;&lt; cl;
return 0;
}

When I try to print this out, I noticed that my stringstream does not reset across the calls done by the for loop in Classroom::read.

This means the output of the main function is:

John Wayne
Scores 100 90 80 100 0
Bob Dwight
Scores 100 90 80 100 0 0 0 10 100
Dummy Student
Scores 100 90 80 100 0 0 0 10 100 0 0

I have tried clear all of my stringstreams with .clear(), and .str(""). They don't work, regardless of where I place them in read(), and in which order. What is curious to me is that quizreader retains all of the previous numbers, but namereader keeps going on and takes the next name as expected. Is this a problem with opening multiple stringstreams? Improper initialization?

I am assuming all inputs are of the correct type, those problems I will be fixing later. I have read almost every post I could find on this site related to this topic, but I cannot seem to find a working solution.

答案1

得分: 1

在你的 Classroom::read 成员函数中,你构造了一个 Student 对象,然后重复使用它来读取每个学生的记录:

void read(istream &amp; in){
    Student s;
    while (in &gt;&gt; s){
        students.insert(students.end(), s);
    }
}

问题在于在 Student::read 函数中,你重复使用了 vector&lt;int&gt; quizzes; 成员,但在学生之间没有调用 .clear() 或清空它。你不断地追加测验分数,这就解释了你的输出。

一个快速的修复方法,对你已经编写的代码进行最少更改,是在读取测验分数之前调用 quizzes.clear();。这可以确保在读取新值之前向量是空的。

注意:当向 std::vector 的末尾添加一个值时,你可以简单地使用 students.push_back(s);,而不是使用 students.insert(students.end(), s);

英文:

In your Classroom::read member function you construct a Student object that is reused to read each student record:

void read(istream &amp; in){
Student s;
while (in &gt;&gt; s){
students.insert(students.end(), s);
}
}

The problem is that in the Student::read function you reuse the vector&lt;int&gt; quizzes; member for each student but you never .clear() or empty it between students. You keep appending quiz scores. That explains your output.

A quick fix, with minimal changes to what you've written, is to call quizzes.clear(); before reading quiz scores. That ensures the vector is empty before reading new values.

Note: When adding a value to the end of a std::vector, instead of doing students.insert(students.end(), s); you can just say students.push_back(s);.

答案2

得分: 0

你通过使用 std::stringstreamstd::istreamstd::getline 来处理事情,增加了不必要的复杂性。你可以简单地使用 std::istream,而不使用其他东西。只需进行额外的状态管理。

至于在 quizzes 中保留值,你可以在 Classroom::read() 中稍微更改你的读取逻辑。

#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;

// Name ... Scores ... Name ... Scores ...
class Student
{
    string first_name;
    string last_name;
    vector<int> quizzes;
public:
    friend istream& operator >>(istream& in, Student& student){
        student.read(in);
        return in;
    }

    void read(istream& in)
    {
        string token;
        int state = 0;  // 0 - name, 1 - scores
        int name_cnt = 0;
        
        while (in >> token)
        {
            if (token.empty())
                continue;
            
            if (state == 1 && token == "Name")
            {
                break;
            }
            
            if (token == "Name")
            {
                state = 0;
                continue;
            }
            else if (token == "Scores")
            {
                name_cnt = 0;
                state = 1;
                continue;
            }
            
            if (state == 0)
            {
                if (name_cnt == 0)
                    first_name = token;
                else
                    last_name = token;
                name_cnt++;
            }
            else if (state == 1)
            {
                quizzes.push_back(std::stoi(token));
            }
        }
        cout << first_name << ' ' << last_name << '\n';
        for (auto x : quizzes) cout << x << ' '; cout << '\n';
    }
};

class Classroom
{
public:
    void read(istream& in){
        while (true)
        {
            Student s;
            if (in >> s)
                students.push_back(s);
            else
                break;
        }
    }
private:
    friend istream& operator >>(istream& in, Classroom& cl){
        cl.read(in);
        return in;
    }
    
    vector<Student> students;
};
int main()
{
    ifstream in("sample.txt");
    if (!in.is_open())
    {
        return 1;
    }
    Classroom C;
    C.read(in);
    return 0;
}
英文:

You are unnecessarily complicating things by using std::stringstream, std::istream and std::getline. You can simply use std::istream without using anything else. Only you have to do additional state management.

As for retained values in quizzes, you can change your reading logic a bit in Classroom::read().

#include &lt;fstream&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
using namespace std;
// Name ... Scores ... Name ... Scores ...
class Student
{
string first_name;
string last_name;
vector&lt;int&gt; quizzes;
public:
friend istream &amp; operator &gt;&gt;(istream &amp;in, Student &amp; student){
student.read(in);
return in;
}
void read(istream&amp; in)
{
string token;
int state = 0;  // 0 - name, 1 - scores
int name_cnt = 0;
while (in &gt;&gt; token)
{
if (token.empty())
continue;
if (state == 1 &amp;&amp; token == &quot;Name&quot;)
{
break;
}
// cout &lt;&lt; token &lt;&lt; &#39;\n&#39;;
if (token == &quot;Name&quot;)
{
state = 0;
continue;
}
else if (token == &quot;Scores&quot;)
{
name_cnt = 0;
state = 1;
continue;
}
if (state == 0)
{
if (name_cnt == 0)
first_name = token;
else
last_name = token;
name_cnt++;
}
else if (state == 1)
{
quizzes.push_back(std::stoi(token));
}
}
cout &lt;&lt; first_name &lt;&lt; &#39; &#39; &lt;&lt; last_name &lt;&lt; &#39;\n&#39;;
for (auto x : quizzes) cout &lt;&lt; x &lt;&lt; &#39; &#39;; cout &lt;&lt; &#39;\n&#39;;
}
};
class Classroom
{
public:
void read(istream &amp; in){
while (true)
{
Student s;
if (in &gt;&gt; s)
students.push_back(s);
else
break;
}
}
private:
friend istream &amp; operator &gt;&gt;(istream &amp;in, Classroom &amp; cl){
cl.read(in);
return in;
}
vector&lt;Student&gt; students;
};
int main()
{
ifstream in(&quot;sample.txt&quot;);
if (!in.is_open())
{
return 1;
}
Classroom C;
C.read(in);
return 0;
}

huangapple
  • 本文由 发表于 2023年3月9日 14:23:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75681069.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定