Gestion et Tri des Données d'Étudiants en C++

Gestion des Concurrents de Compétition

Structure Contestant

La structure Contestant représente un participant à une compétition, stockant son identifiant, nom, spécialité, nombre de problèmes résolus et temps de pénalité.

#pragma once
#include <iomanip>
#include <iostream>
#include <string>

struct Contestant {
    long   id;
    std::string name;
    std::string major;
    int    solved;
    int    penalty;
};

// Surcharge de l'opérateur << pour l'affichage formaté
inline std::ostream& operator<<(std::ostream& out, const Contestant& c) {
    out << std::left;
    out << std::setw(15) << c.id
         << std::setw(15) << c.name
         << std::setw(15) << c.major
         << std::setw(10) << c.solved
         << std::setw(10) << c.penalty;
    return out;
}

// Surcharge de l'opérateur >> pour la lecture des données
inline std::istream& operator>>(std::istream& in, Contestant& c) {
    in >> c.id >> c.name >> c.major >> c.solved >> c.penalty;
    return in;
}
</string>

Fonctions Utilitaires

Ce fichier fournit des fonctions pour trier les concurrents selon les règles de l'ACM (nombre de problèmes résolus décroissant, puis temps de pénalité croissant), écrire les résultats dans un flux de sortie, imprimer à l'écran, sauvegarder dans un fichier et charger depuis un fichier.

#pragma once
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "contestant.hpp"

// Fonction de comparaison pour le tri selon les règles ACM
inline bool compareContestants(const Contestant& a, const Contestant& b) {
    if (a.solved != b.solved) {
        return a.solved > b.solved; // Décroissant par problèmes résolus
    }
    return a.penalty < b.penalty; // Croissant par pénalité
}

// Écrit un vecteur de concurrents dans un flux de sortie donné
inline void writeResults(std::ostream& os, const std::vector& contestants) {
    for (const auto& contestant : contestants) {
        os << contestant << '\n';
    }
}

// Affiche les résultats à l'écran
inline void displayResults(const std::vector& contestants) {
    writeResults(std::cout, contestants);
}

// Sauvegarde les résultats dans un fichier spécifié
inline void saveResultsToFile(const std::string& filename, const std::vector& contestants) {
    std::ofstream outputFile(filename);
    if (!outputFile) {
        throw std::runtime_error("Impossible d'ouvrir le fichier pour écriture : " + filename);
    }
    writeResults(outputFile, contestants);
}

// Charge les données des concurrents depuis un fichier, en ignorant la ligne d'en-tête
inline std::vector loadContestantsFromFile(const std::string& filename) {
    std::ifstream inputFile(filename);
    if (!inputFile) {
        throw std::runtime_error("Impossible d'ouvrir le fichier pour lecture : " + filename);
    }

    std::string headerLine;
    std::getline(inputFile, headerLine); // Ignorer la ligne d'en-tête

    std::vector contestants;
    Contestant tempContestant;
    int sequenceNumber; // Numéro de séquence lu depuis le fichier

    // Lire les données des concurrents
    while (inputFile >> sequenceNumber >> tempContestant) {
        contestants.push_back(tempContestant);
    }
    return contestants;
}

Application Principale

L'application charge les données des concurrents depuis le fichier data.txt, les trie selon les règles ACM, affiche les résultats à l'écran et sauvegarde le classement dans ans.txt. La gestion des erreurs est assurée par des blocs try-catch.

#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <vector>
#include "contestant.hpp"
#include "utils.hpp" // Supposons que ce fichier contienne les fonctions utilitaires

// Fichiers d'entrée et de sortie
const std::string INPUT_FILENAME = "./data.txt";
const std::string OUTPUT_FILENAME = "./ans.txt";

void runCompetitionApp() {
    std::vector contestants;

    try {
        contestants = loadContestantsFromFile(INPUT_FILENAME);
        std::sort(contestants.begin(), contestants.end(), compareContestants);
        displayResults(contestants);
        saveResultsToFile(OUTPUT_FILENAME, contestants);
    } catch (const std::exception& e) {
        std::cerr << "Erreur : " << e.what() << '\n';
        return;
    }
}

int main() {
    runCompetitionApp();
    return 0;
}

Gestion des Étudiants

Classe Student

La classe Student encapsule les informations d'un étudiant : identifiant, nom, spécialité et note. Elle inclut des méthodes pour accéder à la spécialité et à la note, ainsi que des surcharges d'opérateurs pour l'entrée/sortie.

#pragma once
#include <iostream>
#include <string>
#include <iomanip>

class Student {
public:
    Student() = default;
    Student(int studentId, std::string studentName, std::string studentMajor, int studentGrade);
    ~Student() = default;

    const std::string& getMajor() const;
    int getGrade() const;

    friend std::ostream& operator<<(std::ostream& os, const Student& s);
    friend std::istream& operator>>(std::istream& is, Student& s);

private:
    int id;
    std::string name;
    std::string major;
    int grade; // Note entre 0 et 100
};

Implémentation de Student

Ce fichier implémente le constructeur de Student et les méthodes d'accès, ainsi que les opérateurs de flux pour la lecture et l'écriture des données d'un étudiant.

#include "student.hpp"

Student::Student(int id0, std::string name0, std::string major0, int grade0)
    : id{ id0 }, name{ std::move(name0) }, major{ std::move(major0) }, grade{ grade0 } {}

const std::string& Student::getMajor() const {
    return major;
}

int Student::getGrade() const {
    return grade;
}

std::ostream& operator<<(std::ostream& os, const Student& s) {
    os << std::left;
    os << std::setw(15) << s.id
         << std::setw(15) << s.name
         << std::setw(15) << s.major
         << std::setw(15) << s.grade;
    return os;
}

std::istream& operator>>(std::istream& is, Student& s) {
    is >> s.id >> s.name >> s.major >> s.grade;
    return is;
}

Classe StuMgr

La classe StuMgr gère une collection d'étudiants. Elle offre des fonctionnalités pour charger des données depuis un fichier, trier les étudiants, les afficher à l'écran et les sauvegarder dans un fichier.

#pragma once
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <algorithm>
#include "student.hpp"

class StuMgr {
public:
    void loadData(const std::string& filePath); // Charge les données depuis un fichier (espaces comme séparateurs)
    void sortStudents(); // Trie par spécialité (ordre lexicographique ascendant), puis par note (descendant)
    void printToScreen() const; // Affiche les données à l'écran
    void saveDataToFile(const std::string& filePath) const; // Sauvegarde les données dans un fichier

private:
    void writeToStream(std::ostream &os) const; // Écrit les données dans un flux de sortie quelconque

private:
    std::vector students;
};

Implémentation de StuMgr

Cette implémentation gère le chargement, le tri, l'affichage et la sauvegarde des étudiants. Elle inclut des validations de données et une gestion des erreurs lors des opérations de fichier et de formatage des lignes.

#include "stumgr.hpp"
#include <stdexcept>
#include <iostream> // Pour std::cerr

// Vérifie la validité de l'identifiant et de la note d'un étudiant
bool isValidStudentData(int id, int grade) {
    if (id < 1000 || id > 1100) {
        // std::cerr << "ID invalide : " << id << std::endl;
        return false;
    }
    if (grade < 0 || grade > 100) {
        // std::cerr << "Note invalide : " << grade << std::endl;
        return false;
    }
    return true;
}

void StuMgr::loadData(const std::string& filePath) {
    std::ifstream inputFile(filePath);
    if (!inputFile) {
        throw std::runtime_error("Échec du chargement du fichier : " + filePath);
    }

    std::string lineToSkip;
    std::getline(inputFile, lineToSkip); // Ignorer l'en-tête

    std::string currentLine;
    int lineNumber = 0;
    while (std::getline(inputFile, currentLine)) {
        std::istringstream iss(currentLine);
        lineNumber++;
        int id;
        std::string name;
        std::string major;
        int grade;

        iss >> id >> name >> major >> grade;

        // Vérification du format de la ligne et présence de tous les champs
        if (iss.fail() || (!iss.eof() && iss.peek() != EOF)) {
            std::cerr << "[ERREUR] Ligne " << lineNumber << " : Format incorrect.\n";
            continue; // Passer à la ligne suivante
        }

        // Vérification des limites des données
        if (!isValidStudentData(id, grade)) {
            std::cerr << "[ERREUR] Ligne " << lineNumber << " : Données hors limites.\n";
            continue; // Passer à la ligne suivante
        }

        students.emplace_back(id, std::move(name), std::move(major), grade);
    }
}

// Fonction de comparaison personnalisée pour le tri
bool compareStudents(const Student& a, const Student& b) {
    if (a.getMajor() != b.getMajor()) {
        return a.getMajor() < b.getMajor(); // Tri par spécialité ascendante
    }
    return a.getGrade() > b.getGrade(); // Tri par note descendante
}

void StuMgr::sortStudents() {
    std::sort(students.begin(), students.end(), compareStudents);
}

void StuMgr::printToScreen() const {
    writeToStream(std::cout);
}

void StuMgr::saveDataToFile(const std::string& filePath) const {
    std::ofstream outputFile(filePath);
    if (!outputFile) {
        throw std::runtime_error("Échec de l'ouverture du fichier pour écriture : " + filePath);
    }
    writeToStream(outputFile);
}

void StuMgr::writeToStream(std::ostream& os) const {
    for (const auto& student : students) {
        os << student << '\n';
    }
}

Application de Gestion d'Étudiants

Cette application fournit une interface utilisateur interactive pour gérer les données des étudiants. Elle permet de charger des données depuis un fichier, de les trier, de les afficher et de les sauvegarder. Les erreurs potentielles lors des opérations sont gérées.

#include <iostream>
#include <limits>
#include <string>
#include "stumgr.hpp"

const std::string STUDENT_INPUT_FILE = "./data_bad.txt";
const std::string STUDENT_OUTPUT_FILE = "./ans.txt";

void displayMenu() {
    std::cout << "\n********** Application Simple **********\n"
                 "1. Charger le fichier\n"
                 "2. Trier\n"
                 "3. Afficher à l'écran\n"
                 "4. Sauvegarder dans un fichier\n"
                 "5. Quitter\n"
                 "Votre choix : ";
}

void runStudentManagerApp() {
    StuMgr manager;

    while (true) {
        displayMenu();
        int choice;
        std::cin >> choice;

        // Gérer les erreurs d'entrée pour le choix
        if (std::cin.fail()) {
            std::cout << "Entrée invalide. Veuillez entrer un nombre.\n";
            std::cin.clear(); // Réinitialiser l'état d'erreur
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Ignorer le reste de la ligne
            continue;
        }

        try {
            switch (choice) {
            case 1:
                manager.loadData(STUDENT_INPUT_FILE);
                std::cout << "Chargement réussi.\n";
                break;
            case 2:
                manager.sortStudents();
                std::cout << "Tri terminé.\n";
                break;
            case 3:
                manager.printToScreen();
                std::cout << "Affichage terminé.\n";
                break;
            case 4:
                manager.saveDataToFile(STUDENT_OUTPUT_FILE);
                std::cout << "Exportation réussie.\n";
                break;
            case 5:
                return; // Quitter l'application
            default:
                std::cout << "Choix invalide.\n";
            }
        } catch (const std::exception& e) {
            std::cout << "Erreur : " << e.what() << '\n';
        }
    }
}

int main() {
    runStudentManagerApp();
    return 0;
}

Modifications et Conclusions

L'ajout d'un constructeur pour Student simplifie l'initialisation. Les exceptions sont utilisées pour signaler les erreurs lors des opérations de fichier, interrompant le programme pour une gestion plus robuste. Le chargement des données a été amélioré pour analyser chaque ligne individuellement à l'aide d'un stringstream, permettant de détecter et de signaler les erreurs de formatage ou les données manquantes avant d'ajouter un étudiant à la liste. Les fonctions de comparaison dédiées sont préférées aux expressions lambda pour une meilleure lisibilité.

La gestion des erreurs visuelle et l'utilisation du polymorphisme des flux d'entrée/sortie en C++ simplifient grandement la maintenance du code et des données. Ce projet a permis d'appliquer les concepts appris en classe et de consolider la compréhension des points moins clairs.

Étiquettes: C++ Gestion de fichiers tri de données flux d'entrée/sortie gestion d'erreurs

Publié le 18 juillet à 09h42