将未知数量的后跟双精度数的字符串读入vector

Reading unknown number of strings followed by doubles into a vector

本文关键字:字符串 vector 未知数 双精度      更新时间:2023-10-16

所以,我想要打开一个包含足球队名称的文件,后面跟着其他数据。例如:

Leicester City 38 12 13
West Ham 38 14 15
Schalke04 40 16 17

然后,我将该数据读入对象类型的向量(我有"Team.h")。问题是,有些球队的名字只有1个字符串,有些则有2个或更多,有些甚至在名字中有数字(如schalke04)。那么,我如何打开一个文件,并正确地读取矢量信息?

#ifndef TEAM_H
#define TEAM_H
#include <string>
using namespace std;
class Team
{
public:
    Team();
    Team(string, double, double, double);
    string getName();
    double getn1();
    double getn2();
    double getn3();
private:
    string name;
    double n1;
    double n2;
    double n3;
};
#endif

Team.cpp

#include "Team.h"
Team::Team()
{
}
Team::Team(string n, double N1, double N2, double N3)
{
    name = n;
    n1 = N1;
    n2 = n2;
    n3 = N3;
}
string Team::getName()
{
    return name;
}
double Team::getn1()
{
    return n1;
}
double Team::getn2()
{
    return n2;
}
double Team::getn3()
{
    return n3;
}

通常在vector中读入像这样

inFile >> name >> n1 >> n2 >> n3;
Team newTeam(name, n1, n2, n3);
teams.push_back(newTeam) //vector<Team>teams declared earlier

UPD:My search method(not good)

string homeTeam;
Team ht;
for (Team team: newTeams)
{
     if(team.getName() == homeTeam)
     {
        ht = team;
     }
}

如果您可以更改Team.hTeam.cpp,请考虑添加

friend istream &operator>>(istream &input, Team &t);
friend ostream &operator<<(ostream &output, Team &t);

从输入流读取数据到Team类的对象,并将整个对象输出到输出流。

我的意思是:

Team.h

#ifndef TEAM_H
#define TEAM_H
#include <string>
using namespace std;
class Team
{
public:
    Team();
    Team(string, double, double, double);
    string getName();
    double getn1();
    double getn2();
    double getn3();
    friend istream &operator>>(istream &input, Team &t);
    friend ostream &operator<<(ostream &output, Team &t);
private:
    string name;
    double n1;
    double n2;
    double n3;
};
#endif

Team.cpp(仅根据相关问题的答案添加新行)

istream &operator>>(istream &input, Team &t)
{
    while (!input.eof() && input.good())
    {
        string s;
        string name;
        getline(input, s);
        if (input.bad() || s.length() == 0)
        {
            input.setstate(ios::badbit); // for case of empty line
            return input;
        }
        istringstream ss(s);
        string str;
        bool notNumber;
        do{
            ss >> t.n1;
            notNumber = ss.fail();
            if (notNumber)
            {
                ss.clear();
                ss >> str;
                //if(name.length() > 0) name.append(" "); // uncomment this if you want spaces in name
                name.append(str);
            }
        } while (notNumber && !ss.eof());
        if (name.length() == 0)
            continue;
        t.name = name;
        if (notNumber)
        {
            input.setstate(ios::badbit);
            return input;
        }
        ss >> t.n2;
        ss >> t.n3;
        if (ss.fail())
        {
            input.setstate(ios::badbit);
            return input;
        }
        return input;
    }
    return input;
}
ostream &operator<<(ostream &output, Team &t)
{
    output << t.getName() << " " << t.getn1() << " " << t.getn2() << " " << t.getn3();
    return output;
}

用法如下:

// reading data from file
vector<Team> dataTable;
while (!inFile.eof() && !inFile.bad())
{
    Team tmp;
    inFile >> tmp;
    if (!inFile.fail())
        dataTable.push_back(tmp);
    else
        inFile.clear();
}
// print data stored in table
for (vector<Team>::iterator i = dataTable.begin(); i != dataTable.end(); i++)
{
    cout << *i << endl;
}

分而治之

将相对复杂的任务分成两个或多个较小的任务。然后执行每一个小任务。每一个小任务都应该比原来的任务更容易。在完成了每一个小任务之后,你就完成了原来的任务。

你的第一步是阅读每个队伍及其得分。输入文件的每一行都给出了这些信息。所以,你的第一个小任务是阅读一个团队的信息价值,一次:

std::string teaminfo;
while (std::getline(std::cin, teaminfo).good())
{
    // Here be dragons.
}

"here be dragons"部分是您将读取teaminfo中的单行文本并对其进行解析的地方。这将是下一个任务,但重点是你现在已经完成了第一个较小的任务:读取一个团队的得分值。现在已经完成了。现在,您需要弄清楚如何提取所需的单个数据块。这将是"here be dragons"部分。

根据我对问题的理解,每行字符串上的最后三项信息是三个分数,由空格分隔。在此之前,其他所有内容都是该队的名称。

因此,当前的任务是从行中删除最后三个以空格分隔的值。这也是一项相对复杂的任务。因此,它也需要被分割,并作为几个独立的小任务来征服。

首要任务是删除读取行末尾的任何无关的空白。您没有指出是否可能在行尾有尾随空格。如果没有,可以省略此步骤。但是,如果需要删除末尾的空白,让我们这样做:

while (!teaminfo.empty() && teaminfo[teaminfo.size()-1] == ' ')
   teaminfo=teaminfo.substr(0, teaminfo.size()-1);

一个相当粗糙的方法,但它已经足够好了。因此,现在尾部的空白已经被修剪。

好,那么剩下的任务就是删除行上的最后三个值。我们再除以这个。让我们从编写一个函数开始,它从行中删除最后一个值,并返回它:

std::string removeLastValue(std::string &line)
{
   size_t p=line.rfind(' ');
   std::string word;
   if (p == std::string::npos) // Edge case, last word.
   {
        p=0;
        word=line;
   }
   else
   {
        word=line.substr(p+1);
   }
   while (p > 0 && line[p-1] == ' ')
      --p;
   line=line.substr(0, p);
   return word;
}

您没有明确当行太短且不包含三个分数的球队名称时,您的预期输入结果是什么。在这里,错误的输入导致返回一个空字符串。

无论如何,最后一个空格之后的所有内容都被提取到word;然后,快速循环在line中最后一个单词之前的空格上进行备份,并将line修剪到该点。我们做完了。

剩下需要完成的任务现在是微不足道的:调用这个函数三次以从teaminfo字符串中删除最后三个值。很明显,剩下的是你们队的名字。此外,每个删除的单词都是std::string,您只需将每个单词转换为double

这是你应该能够自己做的事情,我不需要写出来