3 votes

Lecture d'un nombre inconnu de chaînes de caractères suivies de doubles dans un vecteur

Alors, je veux ouvrir un fichier qui contient les noms des équipes de football suivis d'autres données. Un exemple serait :

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

Ensuite, je lis ces données dans un vecteur de type objet (J'ai "Team.h"). Le problème est que certaines équipes ne contiennent qu'une seule chaîne de caractères comme nom, d'autres en ont 2 ou plus, et certaines contiennent même des chiffres dans le nom (c'est-à-dire Schalke04). Comment faire pour ouvrir un fichier et lire les informations dans le vecteur correctement ?

#ifndef TEAM_H
#define TEAM_H

#include 

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;
}

Normalement, la lecture dans le vecteur ressemblerait à ceci :

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

MAJ: Ma méthode de recherche (pas bonne)

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

2voto

Sam Varshavchik Points 2563

Divise et conquiers.

Divisez votre tâche relativement complexe en deux ou plusieurs tâches plus petites. Ensuite, implémentez chaque tâche plus petite. Chacune des tâches plus petites devrait être plus facile en soi que la tâche originale. Après avoir implémenté chaque petite tâche, vous finissez par implémenter votre tâche originale.

Votre première étape consiste à lire chaque équipe et ses scores. Cette information est donnée sur chaque ligne de votre fichier d'entrée. Ainsi, votre première petite tâche consiste à lire les informations d'une équipe à la fois :

std::string teaminfo;

while (std::getline(std::cin, teaminfo).good())
{
    // Ici résident les dragons.
}

La partie "Ici résident les dragons" est l'endroit où vous prendrez la seule ligne de texte lue dans teaminfo et la analyserez. Ce sera la prochaine tâche, mais l'important est que vous ayez maintenant conquis la première tâche plus petite : lire les scores d'une équipe. C'est maintenant fait. Maintenant, vous devez trouver comment extraire les différentes données que vous voulez. C'est cela la partie "Ici résident les dragons".

D'après ce que je comprends de la question, les trois derniers éléments d'information sur chaque ligne de texte sont les trois scores, séparés par des espaces. Et tout le reste, jusqu'à ce point, est le nom de l'équipe.

Ainsi, la tâche à faire est de supprimer les trois dernières valeurs délimitées par des espaces blancs de la ligne. C'est également une tâche relativement complexe. Donc, elle doit aussi être divisée et conquise en plusieurs petites tâches individuelles.

La première chose à faire est de supprimer les espaces blancs superflus à la fin de la ligne lue. Vous n'avez pas indiqué s'il était possible qu'il y ait des espaces blancs en fin de ligne. Dans le cas contraire, cette étape peut être omise. Mais, si les espaces blancs en fin de ligne doivent être supprimés, faisons-le :

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

Une approche assez basique, mais c'est suffisant. Ainsi, les espaces blancs en fin de ligne ont été supprimés.

Ok, la dernière tâche restante est de supprimer les trois dernières valeurs de la ligne. Divisons cela à nouveau. Commençons par écrire une fonction qui supprime la dernière valeur de la ligne, et la retourne :

std::string removeLastValue(std::string &line)
{
   size_t p=line.rfind(' ');

   std::string word;

   if (p == std::string::npos) // Cas particulier, dernière mot.
   {
        p=0;
        word=line;
   }
   else
   {
        word=line.substr(p+1);
   }

   while (p > 0 && line[p-1] == ' ')
      --p;

   line=line.substr(0, p);

   return word;
}

Vous n'avez pas clarifié quel est le résultat attendu en cas d'entrée incorrecte, lorsque la ligne est trop courte et ne contient pas de nom d'équipe avec trois scores. Ici, une entrée incorrecte aboutit à un retour d'une chaîne vide.

Quoi qu'il en soit, tout après le dernier espace est extrait dans word ; puis, une rapide boucle recule sur les espaces précédant le dernier mot dans la line, et supprime la line jusqu'à ce point. Nous avons terminé.

Les tâches restantes à conquérir sont maintenant triviales : appelez cette fonction trois fois pour supprimer les trois dernières valeurs de la chaîne teaminfo. Ce qui reste est le nom de votre équipe, évidemment. De plus, chaque mot supprimé est de type std::string, et vous devez simplement convertir chacun en un double.

C'est quelque chose que vous devriez être capable de faire par vous-même, et je n'ai pas besoin de l'écrire.

2voto

VolAnd Points 5473

Si vous pouvez modifier Team.h et Team.cpp, pensez à ajouter

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

pour lire les données du flux d'entrée vers l'objet de la classe Team et écrire l'objet complet dans le flux de sortie.

Je veux dire ce qui suit:

Team.h

#ifndef TEAM_H
#define TEAM_H

#include 

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 (seules les nouvelles lignes basées sur la réponse à la question connexe)

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); // pour le cas d'une ligne vide
            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(" "); // décommentez ceci si vous voulez des espaces dans le nom
                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;
}

Et l'utilisation sera comme suit:

// lire les données à partir du fichier
vector dataTable;
while (!inFile.eof() && !inFile.bad())
{
    Team tmp;
    inFile >> tmp;
    if (!inFile.fail())
        dataTable.push_back(tmp);
    else
        inFile.clear();
}
// afficher les données stockées dans la table
for (vector::iterator i = dataTable.begin(); i != dataTable.end(); i++)
{
    cout << *i << endl;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X