如何将字符串片段读入类数组C++

How to read pieces of string into a class array C++

本文关键字:数组 C++ 片段 字符串      更新时间:2023-10-16

我有一个我创建的视频类的DVD数组

Video dvd[10];

每个视频都有属性,

class Video {
string _title;
string _genre;
int _available;
int _holds;
public:
Video(string title, string genre, int available, int holds);
Video();
void print();
void read(istream & is, Video dvd);
int holds();
void restock(int num);
string getTitle();
~Video();
};

我正在尝试用文本文件中的数据填充此数组,其中标题和流派等每个信息都用逗号分隔

Legend of the seeker, Fantasy/Adventure, 3, 2
Mindy Project, Comedy, 10, 3
Orange is the new black, Drama/Comedy, 10, 9

我尝试使用getline(in, line, ','),但是当需要将每一行插入 DVD 阵列时,我的大脑会停止。

我还创建了一个 read 方法来读取由空格分隔的每个单词,但我认为这不是我真正想要的。

我还尝试使用 getline 读取一行,将该行存储在一个字符串中并从那里拆分,但我对这条线感到困惑。

**我可以从每一行中获取我需要的字符串,我的困惑在于如何在 while 循环中将其插入我的类数组中,尤其是当我一次只能阅读一个单词时。

我需要帮助来了解我应该遵循什么方法来解决这个问题。

**我的代码

#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>
#define MAX 10
using namespace std;
class Video {
string _title;
string _genre;
int _available;
int _holds;
public:
Video(string title, string genre, int available, int holds);
Video();
void print();
void read(istream & is, Video dvd);
int holds();
void restock(int num);
string getTitle();
~Video();
};
Video::Video(string title, string genre, int available, int holds){
_title = title;
_genre = genre;
_available = available;
_holds = holds;
}
void Video::read (istream & is, Video dvd)   
{  
is >> _title >> _genre >> _available>>_holds;
dvd = Video(_title,_genre,_available,_holds);
}
int Video::holds(){
return _holds;
}
void Video::restock(int num){
_available += 5;
}
string Video::getTitle(){
return _title;
}
Video::Video(){
}
void Video::print(){
cout<<"Video title: " <<_title<<"n"<<
"Genre: "<<_genre<<"n"<<
"Available: " <<_available<<"n"<<
"Holds: " <<_holds<<endl;
}
Video::~Video(){
cout<<"DESTRUCTOR ACTIVATED"<<endl;
}
int main(int params, char **argv){
string line;
int index = 0;
vector<string> tokens;
//Video dvd = Video("23 Jump Street", "comedy", 10, 3);
//dvd.print();
Video dvd[MAX];
dvd[0].holds();
ifstream in("input.txt");
/*while (getline(in, line, ',')) {
tokens.push_back(line);
}
for (int i = 0; i < 40; ++i)
{
cout<<tokens[i]<<endl;
}*/
if(!in.fail()){
while (getline(in, line)) {
dvd[index].read(in, dvd[index]);
/*cout<<line<<endl;
token = line;
while (getline(line, token, ',')){
}
cout<<"LINE CUT@@@@@"<<endl;
cout<<line<<endl;
cout<<"TOKEN CUT@@@@@"<<endl;*/
//dvd[index] = 
index++;
}
}else{
cout<<"Invalid file"<<endl;
}

for (int i = 0; i < MAX; ++i)
{
dvd[i].print();
}

}

首先,我将Video::read函数更改为operator >>的重载。 这将允许在使用输入流时像使用任何其他类型一样简单地使用Video类。

此外,将read实现为返回void的非静态成员函数的方式并不直观,使用起来非常笨拙。 您将如何编写循环,同时检测到您已到达文件末尾(想象一下,如果只有 3 个项目要读取 - 您怎么知道不尝试读取第四个项目)? 在C++中执行此操作的更好、直观且坦率地说,事实上的方法是使>>运算符过载。

(最后,我展示了如何编写使用重载>>read函数)

class Video
{
//...
public:
friend std::istream& operator >> (std::istream& is, Video& vid);
//..
};

我不会讨论为什么这应该是一个friend函数,因为在这里可以很容易地研究如何重载>>

所以我们需要实现这个函数。 下面是一个在一行中读取并将信息复制到传入vid的实现:

std::istream& operator >> (std::istream& is, Video& vid)
{
std::string line;
std::string theTitle, theGenre, theAvail, theHolds;
// First, we read the entire line
if (std::getline(is, line))
{
// Now we copy the line into a string stream and break 
// down the individual items
std::istringstream iss(line);
// first item is the title, genre, available, and holds
std::getline(iss, theTitle, ',');
std::getline(iss, theGenre, ',');
std::getline(iss, theAvail, ',');
std::getline(iss, theHolds, ',');
// now we can create a Video and copy it to vid
vid = Video(theTitle, theGenre, 
std::stoi(theAvail), // need to change to integer
std::stoi(theHolds)); // same here
}
return is;  // return the input stream
}

请注意vid是引用参数,而不是按值传递。 如果要保留read函数,则需要进行相同的更改。

我们上面所做的是,我们首先使用"外部"调用来读取整行std::getline。 一旦我们将该行作为字符串,我们就通过使用std::istringstream来分解该字符串,并使用适用于istringstream的"内部"getline调用集分隔逗号上的每个项目。 然后,我们只需根据从istringstream检索到的信息创建一个临时Video并将其复制到vid.

下面是一个main函数,现在最多可以读取 10 个项目:

int main()
{
Video dvd[10];
int i = 0;
while (i < 10 && std::cin >> dvd[i])
{
dvd[i].print();
++i;
}
}

因此,如果您查看循环,我们所做的只是 1) 确保我们不会超过 10 个项目,以及 2) 只使用cin >> dvd[i],这看起来就像您在输入项目时日常使用>>。 这就是超载>>的魔力Video.

下面是一个使用您的数据的实时示例。


如果您打算保留read函数,那么如果将返回类型更改为返回true的返回bool会更容易,如果读取或以其他方式false项目,并且只调用operator >>

下面是一个示例:

bool Video::read(std::istream & is, Video& dvd)
{
if (is.good())
{
is >> dvd;
return true;
}
return false;
}

这是main函数:

int main()
{
Video dvd[10];
int i = 0;
while (i < 10 && dvd[i].read(std::cin, dvd[i]))
{
dvd[i].print();
++i;
}
}

现场示例 #2

但是,我仍然说,将Video::read设置为非静态成员会使代码main笨拙。