Partage

[Exercices] Venez vous entraîner !

Ce mois: Parseur de fonctions mathématiques

1 juillet 2008 à 20:17:59

Citation : BoudBoulMan

Donc, en fait dès que t'as au moins 2 sauts à la ligne successifs, il y a un changement de paragraphe.



Pourquoi 2 ? Théoriquement un seul suffit.
1 juillet 2008 à 20:52:14

Ben dans ce cas-là un paragraphe devrait tenir sur une seule ligne !
1 juillet 2008 à 20:54:51

tu peux continuer dans la meme ligne apres un point ;)
1 juillet 2008 à 20:59:59

Citation : Kurlze

Citation : BoudBoulMan

Donc, en fait dès que t'as au moins 2 sauts à la ligne successifs, il y a un changement de paragraphe.



Pourquoi 2 ? Théoriquement un seul suffit.


Non, tu peux avoir des sauts à la ligne dans un paragraphe.
1 juillet 2008 à 21:03:32

pour mettre tout le monde d'accord, rien ne vaut un bon exemple:

Citation : Pas de titre

Il était un jour [...]\n
\n

[...] et vécurent heureux.

1 juillet 2008 à 21:11:53

Non. Ce n'est pas ce que j'ai écrit.

Citation


\n
blabla
\n



Ceci est un paragraphe. Je n'ai pas précisé combien de \n il devait y avoir avant et après. J'ai dit qu'il devait y en avoir (au moins) un avant et (au moins) un après un bloc de texte.
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
1 juillet 2008 à 21:19:37

dans ce cas là il y a un problème avec le paragraphe qui se trouve au début.

Le mieux est de compter le nombre de fois qu'il y a deux retour à la ligne à la suite (\n\n) suivient de plusieurs mots, puis d'incrémenter pour ne pas oublier le dernier OU premier. Cette façon de faire m'a l'air bien, après j'ai peut-etre oublié qqch
1 juillet 2008 à 21:22:04

tu n'as toujours pas vu les participations?
1 juillet 2008 à 21:25:20

Citation : Nanoc

Non. Ce n'est pas ce que j'ai écrit.

Citation


\n
blabla
\n



Ceci est un paragraphe. Je n'ai pas précisé combien de \n il devait y avoir avant et après. J'ai dit qu'il devait y en avoir (au moins) un avant et (au moins) un après un bloc de texte.


Ok, donc une ligne est considérée comme un paragraphe ici?
Si on le définit clairement comme ça pour l'exo, je suis d'accord.
1 juillet 2008 à 21:27:33

Citation : Chlab_lak

dans ce cas là il y a un problème avec le paragraphe qui se trouve au début.

Le mieux est de compter le nombre de fois qu'il y a deux retour à la ligne à la suite (\n\n) suivient de plusieurs mots, puis d'incrémenter pour ne pas oublier le dernier OU premier. Cette façon de faire m'a l'air bien, après j'ai peut-etre oublié qqch



C'est pas un problème, il faut juste y penser. Un texte est composé au minimum d'un paragraphe. Avec ta méthode, tu comptes les sauts de paragraphes. Il peut très bien y avoir 5 retours à la ligne entre deux paragraphes. C'est une question d'esthétique. De plus avec ta méthode, il faut aussi penser au premier paragraphe, puisque il peut potentiellement ne jamais avoir de \n dans un texte.
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
1 juillet 2008 à 21:39:13

Je ne vois toujours pas de problème dans ma méthode, peut-être qu'on se comprend mal.
Voilà à quoi je pense:

size_t 
compter_paragraphe(std::istream &fichier)
{
   size_t nombre_paragraphe = 0;

   /*
   ici, on compte le nombre de fois qu'il y a 
   deux (ou plus)  sauts de ligne à la suite
   suivient de un (ou plusieurs) mots.
   */

   return nombre_paragraphe + 1;
}
2 juillet 2008 à 8:43:50

Citation : http://fr.wikipedia.org/wiki/Paragraphe

En bonne typographie, on appelle paragraphe un segment de texte suivi (dit aussi texte linéaire) compris entre deux alinéas.



Je dis pas que ta méthode ne permet pas le calcul, mais ce n'est pas la définition.
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
2 juillet 2008 à 10:36:25

Faudrait peut-être préciser la définition dans l'énoncé, ça évitera les mauvaises interprétations.
2 juillet 2008 à 11:08:08

Argh en fait c'est pas si facile que ça en a l'air :-° . Le problème c'est que je sais pas trop utiliser les méthodes des chaînes et des fichiers...
2 juillet 2008 à 11:20:35

Le 28, j'ai envoyé ma réponse à l'exercice de compression, mais il n'a toujours pas été regardé....
2 juillet 2008 à 11:23:22

C'est normal, j'attends la fin du mois pour tout regarder. Et après, je fais ça quand j'ai le temps. Ce qui sera le cas vendredi normalement.
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
2 juillet 2008 à 13:28:23

J'ai fini !
(Pour une fois que j'avais du temps libre, j'ai pu faire l'exercice)
Manque plus qu'as faire un jolie code et a bien présenter la console :p .
2 juillet 2008 à 21:20:29

Bonjour a tous.

Etant un peu rouillé en C++ et voulant m'y remettre je viens de découvrir vos petits exercices pile ce qu'il me fallait (simples mais efficaces, puis j'ai pas le temps de mettre au gros concours (boulot quand tu nous tiens)).

Donc je pense me joindre à vous pour l'exercice de juillet (quasiment fini d'ailleurs).

Néanmoins quelques précisions sur les résultats attendus: quels qont les caractères a comptabiliser (les \n \t ...) sont-ils des caractères. Quels sont les séparateurs de mots à prendre en compte( , ; . ...)

Je demande car impossible d'obtenir le même résultat que word ou open office (qui eux même n'ont pas le même résultat....)

On est juste d'accord sur le nombre de paragraphes, pour le reste j'ai un résultat entre les 2...

Merci pour ces quelques pécisions

EDIT: Finalement j'ai trouvé les paramètre utilisés par word, j'arrive au même résultat: dont-on prendre ces paramètres ou ceux de OO (ou autre...)
2 juillet 2008 à 22:06:18

Citation : moa3788

Néanmoins quelques précisions sur les résultats attendus: quels qont les caractères a comptabiliser (les \n \t ...) sont-ils des caractères. Quels sont les séparateurs de mots à prendre en compte( , ; . ...)


\n et \t sont bien des caractères à comptabiliser pour le nombre total de caractères mais pas dans celui de caractères sans espaces
vu que les espaces c'est l'espace, \n, \t, ... ou sinon cela n'aurait aucun rapport de différencier les deux.

Pour les séparateurs de mot, j'en sais rien :euh:
2 juillet 2008 à 22:34:06

on peut essayer de le faire avec Qt ou seulement avec la console ?
merci
3 juillet 2008 à 10:47:18

Pour ceux qui voudrait utiliser des caractères accentués dans leur tableau de statistiques, comme par exemple:
+----------------------------------------+--------+
| Nombre de caractères                   |       0|
| Nombre de caractères (hors espace)     |       0|
| Nombre de mots                         |       0|
| Nombre de paragraphes                  |       0|
+----------------------------------------+--------+

Et si vous utilisez le manipulateur setw pour cela, sachez que les caractères accentués comptent pour deux caractères et les caractères ajoutés ne rempliront plus le même espace.

Ici par exemple, il faut normalement spécifier setw(40) pour remplir correctement la colonne de gauche mais pour "Nombre de caractères" et "Nombre de caractères (hors espace)", il faut indiquer setw(41) par le fait qu'il y a un caractère accentué qui "occupe" une place de plus.

Voilà, si ça peut aider certains qui auront ce problème.
Anonyme
3 juillet 2008 à 13:02:10

Citation : kudo2

on peut essayer de le faire avec Qt ou seulement avec la console ?
merci

Non pas de Qt. Sinon ce serait indiqué.
3 juillet 2008 à 13:51:08

@BoudBoulMan, c'est parce que tu dois bosser en utf-8.
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
3 juillet 2008 à 18:06:49

@moa3788: Tous les caractères affichables comptent ensuite les autres comme \t, \n ,... vont dans la catégorie "espaces". Je ne sais pas exactement comment comptent OOo et Word, c'était juste pour donner une idée.

@kudo2: Tu peux faire une interface Qt si ça t'intéresse. Néanmoins la correction n'en aura pas et il ne sert donc à rien d'envoyer ton code dans ce cas, car il ne pourra servir de correction.

@Bouboulman: Ca dépend des paramètres de ta console en fait.
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
3 juillet 2008 à 21:15:29

Ok, merci pour la précision.

Et également, ce n'est pas très grave si on utilises la classe ifstream et que donc il y a quelques problèmes au niveau du comptage de caractères de fichiers utf-8?
3 juillet 2008 à 21:24:53

Non,non. C'est le principe qui compte. L'affichage on s'en fout un peu. (Mais pas trop quand même)
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
5 juillet 2008 à 11:51:43

Solution du mois de juin 2008



Bonjour tout le monde ! Il est temps que je dévoile une solution pour l'exercice du mois de juin . Vous avez été 22 à m'envoyer une solution. Parmi celles-ci plusieurs ne correspondaient pas exactement à la donnée et d'autres étaient trop complexes (même si correctes) pour faire office de corrigé.
J'ai finalement retenu la solution de lanfeusst.

Solution complète



Cet exercice avait principalement deux difficultés, la première consistait à lire un fichier texte ligne par ligne. La deuxième était de gérer proprement tous les cas donnés dans l'algorithme RLE.

Lecture ligne-par-ligne:

Il fallait pour cela se rappeler de la fonction getline() et de sa syntaxe un peu inhabituelle.

getline(flux, string);


Il fallait ègalement se souvenir que cette fontion renvoit un booléen indiquant si la lecture peut continuer. Ceci est très pratique pour savoir quand se termine le fichier (ou si un erreur survient)comme cela est fait dans le code source ci-dessous.

Compression des lignes:

Plusieurs méthodes sont ici possibles, la plus simple étant de parcourir la chaîne de caractère et de créer une nouvelle chaine avec les modifications nécessaires comme donné dans la donnée de l'exercice.
On pouvait également utiliser un itérateur ou ne pas créer une nouvelle chaine de caractère. Tous ces choix sont valables.

Gestion des exceptions


Gérer les exceptions dans cet exercice était un petit plus. Le code ci-dessous utilise des strings comme exception. Cette approche est valable mais ne permet pas de récupérer les exceptions standards qui pourraient être lancées par la bibliothèque standard.
Le mieux aurait été de créer sa propre classe d'exception dérivée de la classe standard ou alors d'utiliser les eceptions standards comme std::runtime_error par exemple.

Je vous laisse avec le code source. Si vous aves des questions, n'hésitez-pas, je complèterai en conséquence.

Programme complet



Voici le code source qu'il a proposé.

main.cpp :

#include <iostream>

using namespace std;

int gereArguments(char argc,char *argv[]);
void afficheAide();
void compression(const string&,char, const string&);
void decompression(const string&,char, const string&);

int main(char argc,char *argv[])
{
    bool retour;
    /* on envoit les arguments à la fonction pour qu'elle appelle les fonctions de compressions
       ou de décompression :                                                                   */
    try
    {
        retour = gereArguments(argc,argv);
    }

    catch (const string& exceptions)// on récupère les exceptions et on les affiche
    {
        cerr<<exceptions;
        retour = EXIT_FAILURE;
    }
    return retour;
}


int gereArguments(char argc,char *argv[])
{
    if (argc < 3)// si il n'y pas assez d'arguments
    {
        afficheAide();
        return(EXIT_FAILURE);
    }


    string CheminFichier = argv[argc-1];
    string Argument1 = argv[1];// On récupère l'argument de la compression ou décompression

    char flag = '@';
    string FichierResultat = CheminFichier;
    if (argc>3)
    {
        string Argument2 = argv[2];
        if (Argument2.substr(0,2)=="-f")// si l'utilisateur veut préciser le flag
        {
            if (Argument2.size()>4)
                throw string("Le flag ne doit être constitué que d'un seul caractère.\n");
            else if (Argument2.size()<4)
            {
                afficheAide();
                return EXIT_FAILURE;
            }
            flag = Argument2[3];
            if (flag=='3'||flag=='4'||flag=='5'||flag=='6'||flag=='7'||flag=='8'||flag=='9')
                throw string("Le flag ne peut pas être un chiffre supérieur à 2.\n");// pour éviter des problèmes à la décompression
            if (argc==5) // si l'utilisateur veut aussi préciser la destination
            {
                string Argument3 = argv[3];
                if (Argument3.substr(0,2)=="-n"&&Argument3.size()>3)
                    FichierResultat = Argument3.substr(3,Argument3.size());
                else
                {
                    afficheAide();
                    return EXIT_FAILURE;
                }
            }
            else if (argc>5)
            {
                afficheAide();
                return EXIT_FAILURE;
            }
        }
        else if (Argument2.substr(0,2)=="-n"&&Argument2.size()>3) // si l'utilisateur veut seulement préciser la destination
            FichierResultat = Argument2.substr(3,Argument2.size());
        else
        {
            afficheAide();
            return EXIT_FAILURE;
        }
    }
    if (Argument1=="-c")
        // On compresse avec les options (changées ou pas par l'utilisateur)
        compression(CheminFichier,flag,FichierResultat);
    else if (Argument1=="-d")
        // On décompresse avec les options (changées ou pas par l'utilisateur)
        decompression(CheminFichier,flag,FichierResultat);
    else
        afficheAide();

    return EXIT_SUCCESS;
}

void afficheAide()
{
    cout<<"Utiliser ce programme de cette manière :"<< endl<<endl<<
    "Pour la compression, utilisez le parametre -c"<<endl<<endl<<
    "Pour la décompression, utilisez le parametre -d"<<endl<<endl<<
    "Si vous voulez utiliser un flag spécifique :"<<endl<<"Utilisez le paramètre -f=\"flag\""
    "dans lequel vous remplacez flag par la lettre"<<endl<<"(Attention il est nécessaire"
    " d'utiliser le même flag pour la compression et la"<<endl<<"décompression)"<<endl<<endl<<
    "Si vous ne souhaitez pas écraser le fichier original(compressé ou décompressé) :"<<endl<<
    "Vous pouvez indiquer la destination en utilisant le paramètre -n=\"fichier_dest\""<<endl<<endl<<
    "Il est nécessaire d'indiquer le fichier à compresser ou à décompresser à la fin"<<endl<<endl<<
    "Exemple : RLE -c -f=\"&\" mon_fichier.txt"<<endl<<
    "Compresse le fichier \"mon_fichier.txt\" en utilisant le flag &"<<endl<<endl<<
    "RLE -d -n=\"fichier.decompr\" fichier.rle"<<endl<<
    "Décompresse le fichier \"fichier.rle\" dans \"fichier.decompr\" en utilisant"<<endl<<
    "le flag par défaut"<<endl<<endl;
}



compression.cpp :

//gère la compression ainsi que la fonction de réecriture

#include <iostream>
#include <fstream>
#include <cstdio> //pour la suppression du fichier

using namespace std;

string transformePetit(const string&,char);
//Compresse une chaine de caractere selon les regles du RLE

void reecrit(const string&,const string&, const string&);
//Copie un fichier dans un autre et supprime le premier fichier

//-------------------------------------------------------------------------------------------------

void compression(const string& CheminACompresser,char flag, const string& CheminResultat)
{
    cout<< "compression en cours..."<<endl;

    // On ouvre les fichiers et on teste les ouvertures en lancant des exceptions si besoin
    ifstream FichierSource(CheminACompresser.c_str(), ios::in);

    if (FichierSource.fail())
        throw string("Impossible d'ouvrir le fichier à compresser :\n"+CheminACompresser+"\n");

    const string CheminACompresserTemp = CheminACompresser + ".rle.tmp"; //fichier temporaire qui sera supprimé à la fin
    ofstream FichierResultat(CheminACompresserTemp.c_str(), ios::out | ios::trunc);

    if (FichierResultat.fail())
        throw string("Impossible d'ouvrir le fichier dans lequel on veut compresser :\n");

    //Variables temporaires pour la compression
    string LigneActuelle, LigneConverti;
    unsigned int nombreDeCaractereAvant = 0, nombreDeCaractereApres = 0;
    unsigned int pourcentage = 0;

    // La boucle parcourt tout le fichier ligne par ligne
    while (getline(FichierSource,LigneActuelle))
    {
        // On compresse la ligne actuelle
        LigneConverti = transformePetit(LigneActuelle,flag);

        // On compte les caractères pour afficher le taux de compression
        nombreDeCaractereAvant += LigneActuelle.size();
        nombreDeCaractereApres += LigneConverti.size();

        // on inscrit la ligne compressée dans le fichier temporaire
        FichierResultat<<LigneConverti;

        if (!FichierSource.eof())// et on rajoute une ligne si on a pas atteint la fin du fichier
            FichierResultat<<endl;
    }

    // On calcule le pourcentage et on l'affiche
    cout<<"compression terminée sans erreur : ";
    pourcentage = static_cast<int>(nombreDeCaractereApres*100.0/nombreDeCaractereAvant);
    cout<<"Le fichier fait "<<pourcentage<<" % de sa taille originale."<<endl;
    
    //On gere le cas ou la compression a ete inefficace
    string Continuer = "O";

    if (pourcentage>100.0) // On affiche un message de confirmation
    {
        cout<<"Le taux de compression est mauvais, peut-être essayez vous de compresser"<<endl<<
        "un fichier déjà compressé ?"<<endl<<
        "Sinon il est peut-être nécessaire d'essayer avec un autre flag (option -f)"<<endl<<endl<<
        "Souhaitez vous continuez [O/n] ? ";
        cin >> Continuer;
    }
    
    //On ferme les deux fichiers
    FichierSource.close();
    FichierResultat.close();

    // On réecrit le contenu du fichier temporaire dans le fichier de destination et on supprime
    // le fichier temporaire                                                               
    reecrit(CheminACompresserTemp,Continuer, CheminResultat);
}

//-------------------------------------------------------------------------------------------------

string transformePetit(const string& LigneActuelle, char flag)
{
    char caractereActuel =' ', ancienCaractere=' ';
    int nombreDePresence = 0;
    string LigneConverti;

    // tant que la fin de la ligne n'est pas atteinte
    for (unsigned int i = 0;i<=LigneActuelle.size();i++)
    {
        if (i>=1)
            ancienCaractere = caractereActuel;

        caractereActuel = LigneActuelle[i];

        if (ancienCaractere==flag&&i>=1)// Si il y a un flag dans le texte
        {
            LigneConverti = LigneConverti + flag + flag;
            nombreDePresence = 1;
        }

        // Si le caractère actuel est le même que celui d'avant
        else if (ancienCaractere==caractereActuel&&i>=1&&nombreDePresence<9)
            nombreDePresence++;

        // Sinon si le nombre de présence est <= 2 on les affiche normalement
        else if (nombreDePresence<=2)
        {
            for (int j = 0;j<nombreDePresence;j++)
                LigneConverti+=ancienCaractere;
            nombreDePresence = 1;
        }

        // Si le nombre de présence est > 2 on les affiche compressés (nombre,flag,caractère)
        else
        {
            char nombre = nombreDePresence +48;
            LigneConverti = LigneConverti +nombre+ flag + ancienCaractere;
            nombreDePresence = 1;
        }
    }

    return LigneConverti;
}

//-------------------------------------------------------------------------------------------------

void reecrit(const string& FichierAReecrire,const string& continuer,const string& CheminResultat)
{
    if (continuer=="O"||continuer=="o")// Si l'utilisateur a continué
    {
        // On ouvre les fichiers et on vérifie les ouvertures en lancant des exceptions si besoin
        ifstream FichierSource(FichierAReecrire.c_str(), ios::in);
        ofstream FichierResultat(CheminResultat.c_str(), ios::out | ios::trunc);

        if (FichierSource.fail())
            throw string("Problème interne : fichier1\n");

        if (FichierResultat.fail())
            throw string("Problème interne : fichier2\n");

        string LigneActuelle;
        // on recopie tout le fichier temporaire dans le fichier définitif
        while (getline(FichierSource,LigneActuelle))
        {
            FichierResultat<<LigneActuelle;
            if (!FichierSource.eof())
                FichierResultat<<endl;
        }
        FichierSource.close();
        FichierResultat.close();

    }

    // Suppression du fichier temporaire 
   remove(FichierAReecrire.c_str());

}


decompression.cpp :

// gère la decompression

#include <iostream>
#include <fstream>

using namespace std;

string transformeGrand(const string&,char);
//Decompresse une chaine de caractere selon les regles du RLE

void reecrit(const string&,const string&,const string&);
//Copie un fichier dans un autre et supprime le premier fichier

void decompression(const string& CheminADecompresser,char flag, const string& CheminResultat)
{
    cout<< "décompression en cours..."<<endl;

    // On ouvre les fichiers et on teste les ouvertures en lancant des exceptions si besoin
    ifstream FichierSource(CheminADecompresser.c_str(), ios::in);

    if (FichierSource.fail())
        throw string("Impossible d'ouvrir le fichier à compresser :\n");

    const string CheminADecompresserTemp = CheminADecompresser + ".rle.tmp";
    ofstream FichierResultat(CheminADecompresserTemp.c_str(), ios::out | ios::trunc);

    if (FichierResultat.fail())
        throw string("Impossible d'ouvrir le fichier dans lequel on veut decompresser :\n");

    //Variables temporaires pour la decompression
    string LigneActuelle, LigneConverti;

    // La boucle parcourt tout le fichier ligne par ligne
    while (getline(FichierSource,LigneActuelle))
    {
        // On décompresse la ligne
        LigneConverti = transformeGrand(LigneActuelle,flag);

        // On l'inscrit dans le fichier temporaire
        FichierResultat<<LigneConverti;
        if (!FichierSource.eof())
            FichierResultat<<endl;
    }

    cout<<"décompression terminée sans erreur"<<endl;

    FichierSource.close();
    FichierResultat.close();

    // On réecrit le fichier temporaire dans le fichier de destination
    reecrit(CheminADecompresserTemp,"0", CheminResultat);
}
string transformeGrand(const string& LigneActuelle,char flag)
{

    string LigneConverti;

    // On utilise ces variables pour ne pas se casser la tête avec des LigneActuelle[...] à répétition
    char prochainCaractere =' ', caractereActuel =' ', dernierCaractere =' ', avantDernierCaractere =' ', apresProchainCaractere =' ';
    int nombreDePresence = 0, nombreDeFlagSuccessif = 0;
    unsigned int finDeLigne = LigneActuelle.size();
    bool pasFlag = false;


    for (unsigned int i = 0;i<LigneActuelle.size();i++)
    {
        // On n'initialise les variables que si on n'a le droit de le faire (attention aux début et fin de ligne)
        if (i>=2)
            avantDernierCaractere = dernierCaractere;
        if (i>=1)
            dernierCaractere = caractereActuel;
        caractereActuel = LigneActuelle[i];
        if (i+1<=finDeLigne)
            prochainCaractere = LigneActuelle[i+1];
        if (i+2<=finDeLigne)
            apresProchainCaractere = LigneActuelle[i+2];

        // Permet de vérifier que le fichier a déjà été compressé (test à la fin)
        if (caractereActuel==flag)
            nombreDeFlagSuccessif++;
        else
            nombreDeFlagSuccessif = 0;

        // Si les caractères ont été compressés sous la forme |nombre|flag|caractere|
        if (dernierCaractere ==flag&&caractereActuel!=flag&&avantDernierCaractere!=flag&&i>=2)
        {
            nombreDePresence = avantDernierCaractere;
            nombreDePresence-=48;

            for (int j = 0;j<nombreDePresence;j++)
                LigneConverti+=caractereActuel;
        }
        // Le caractère n'est pas écrit sous forme compressé:

        // Si le caractère est entouré de 2 autres caractères non flag
        else if ((dernierCaractere!=flag&&caractereActuel!=flag&&prochainCaractere!=flag&&i>=1)||
                 // Ou si il est en début de ligne et que le prochain caractère n'est pas un flag
                 (caractereActuel!=flag&&prochainCaractere!=flag&&i==0)||
                 // Ou si il est en début de ligne et que les 2 prochains caractères sont des flags
                 (caractereActuel!=flag&&prochainCaractere==flag&&apresProchainCaractere==flag&&i==0)||
                 // Ou si il est suivi d'au moins 2 flags et précédé par un caractère normal
                 (prochainCaractere==flag&&apresProchainCaractere==flag&&caractereActuel!=flag&&dernierCaractere!=flag&&i>=1&&i+2<=finDeLigne)||
                 // Ou l'inverse
                 (avantDernierCaractere==flag&&dernierCaractere==flag&&caractereActuel!=flag&&prochainCaractere!=flag&&i>=2&&i+1<=finDeLigne)||
                 // Ou si il est précédé par 2 flags et suivi par 2 flags
                 (avantDernierCaractere==flag&&dernierCaractere==flag&&caractereActuel!=flag&&prochainCaractere==flag&&apresProchainCaractere==flag&&i>=2&&i<=finDeLigne))
        {
            LigneConverti+=caractereActuel;
        }
        // Si il y a 2 flags de suite ou plus :
        else if (caractereActuel==flag&&dernierCaractere==flag&&i>=1)
        {
            if (pasFlag)// Si on ne vient pas d'en écrire un
            {
                // On l'écrit
                LigneConverti +=flag;
                pasFlag = false;
            }
            else // Si on vient d'en écrire un
                pasFlag = true;
        }

        else
        {
            pasFlag = true;
            if (nombreDeFlagSuccessif%2==1&&nombreDeFlagSuccessif!=1) // On vérifie le nombre de flags successifs
            {
                string StrFlag;
                StrFlag += flag;
                throw string("Le fichier n'avait pas été compressé ou avait été compressé avec un flag différent\n"
                             "de celui-ci ("+StrFlag+"), ou a été corrompu par la suite.\nAnnulation.\n");
            }
        }
        // On vérifie qu'il n'y a pas plus de 2 caractères identiques
        if (dernierCaractere==caractereActuel&&caractereActuel==prochainCaractere&&i>=1&&dernierCaractere!=flag&&i>=1&&i+1<=finDeLigne)
        {
            // Il est aussi possible qu'il y en est 3 si le premier est précédé par un flag :
            // Si il y en a 3 mais que le premier n'est pas précédé par un flag :
            if (i>=3&&avantDernierCaractere==dernierCaractere&&LigneActuelle[i-3]!=flag)
            {
                // On envoie une exception avec le flag utilisé
                string StrFlag;
                StrFlag += flag;
                throw string("Le fichier n'avait pas été compressé ou avait été compressé avec un flag différent\n"
                             "de celui-ci ("+StrFlag+"), ou a été corrompu par la suite.\nAnnulation.\n");
            }
        }
    }
    return LigneConverti;

}


Il me semble que les commentaires et les noms de variables situés dans le code devrait permettre de comprendre les étapes un peu plus complexes de l'algorithme. Si ce n'est pas le cas, dites-le et j'en ajouterai


Remarques sur les codes reçus



  • Lisez bien toute la donnée. Il ne sert à rien de faire autre chose.
  • En C++, évitez les FILE* et autres moyens de gestion des fichiers venus du C. Les flux sont plus puissants et plus sécurisés.
  • De même, évitez les printf() et surtout ne mélangez pas printf() et les cout <<.
  • Ne mettez pas de using namespace std; dans des .h


Il ne sert à rien d'envoyer votre code si il ne fonctionne pas ou pire, si il ne compile pas.


Merci à tous ceux qui ont participé. Et bonne chance avec l'exercice suivant !
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
5 juillet 2008 à 12:09:34

Euh, simple question:
Pour l'exercice des statistiques de fichier, on peut aller plus loin? Cela compenserait un peu la facilité et le manque de niveau, non?