/* IFT1169 - démonstration #06 - exercice 06 - Fichier d'en-tête - 21-février -2006 v1.08 M.Lokbani - destructeur à part + gcc3.4.2 07-décembre -2003 v1.07 M.Lokbani - comments + gcc3.2 + MinGW/Cygwin/Linux 11-novembre -2000 v1.06 M.Lokbani - gcc2.95 18-juin -2000 v1.05 M.Lokbani - la même chose en Perl 12-juin -2000 v1.04 M.Lokbani - mise à jour pour E00 30-mars -2000 v1.03 M.Lokbani - modification dans le destructeur au niveau de la commande system 03-decembre -1999 v1.02 M.Lokbani - +comments + ajout de la commande system 24-novembre -1999 v1.01 P.Langlais - solution 23-novembre -1999 v1.00 M.Lokbani - l'énoncé contact: lokbani@iro.umontreal.ca Copyright (C) 1999-2006 Université de Montréal Département d'informatique et de Recherche Opérationnelle Mohamed Lokbani -- Tous Droits Réservés -- All Rights Reserved -- Description: ------------ Lecture d'un fichier texte, recherche d'une chaîne de caractères, et remplacement de la chaîne si elle existe par une autre chaîne de caractères. Une approche optimisée consiste à utiliser une solution à base d'une méthode de recouvrement "overlap". Elle consiste à lire dans un buffer tampon de M caractères que N caractères, où: si la taille de la nouvelle chaîne est inférieure à la taille de la chaîne à remplacer, alors pas de danger pour que N=M. Dans le cas contraire, M-N = taille de la nouvelle chaîne - taille chaîne à remplacer Exemple: Si le buffer est de taille M=1000 char. La nouvelle chaîne: "ouvrir la fenêtre", sa taille est: 17 char L'ancienne chaîne: "jours", sa taille est: 5 Alors la taille de la chaîne a lire est de N = 1000 - 17 - 5 = 978 char. Puis on glisse la fenêtre de lecture sur la totalité du fichier. Ainsi on utilisera qu'un seul fichier pour réaliser l'opération de recherche et remplacement. Nous allons vous proposer une solution terre à terre plus simple à suivre. La solution proposée suit une approche à deux fichiers. Le premier contenant le texte original. Le second le résultat après la procédure recherche et remplacement. Ainsi on ouvre le fichier original en lecture. En le parcourant, on préserve son contenu dans un buffer de taille donnée. On recherche dans ce buffer si la chaîne est présente, si oui on la remplace, sinon le buffer reste inchangé. On écrit le contenu de ce buffer dans le fichier de sortie. Avant de terminer l'exécution du programme, on détruit le fichier original, pour le remplacer par le fichier de sortie (résultant), pour n'avoir qu'un fichier (pas de duplication). En Perl pour faire ce qui a été décrit précédemment: perl -i -pne 's/tempete/fausse alerte \!/' essai.txt Perl cherche dans le fichier essai.txt la chaîne tempete et la remplace par la chaîne: fausse alerte! Le travail se fait sur le même fichier. Attention: On a utilise une commande system pour montrer l'interaction Unix/C++ mv fichier_temporaire fichier_original Cette commande permet de: -1- Effacer, delete, le "fichier_original" du disque. -2- Renommer fichier_temporaire avec le nom de fichier_original À la fin de cette opération, il n'y aura qu'un seul fichier, celui en entrée mais remis à jour. Vous allez rencontrer durant cette opération un problème avec le chemin exact pour arriver à la commande mv. Sous Linux ou Windows (Cygwin ou MinGW) cette commande se trouve dans: /bin/mv Ainsi sur Linux, le chemin vers /bin/mv va être trouvé sans problème sous la condition qu'il existe et que le path soit correctement configuré. Sous Windows c'est toute une autre histoire .... Si vous compilez sous Cygwin avec le chemin correctement configuré et sous la condition aussi que /bin/mv existe, la aussi aucun problème! Par contre sous MinGW préparez vos nerfs! Vous allez en effet obtenir l'erreur suivante: The system cannot find the path specified. Comment dire à un MinGW de résoudre ce chemin? Modifier la variable d'environnement système path? Toujours le même problème à l'arrivée! Que faire alors? Cygwin est système de développement très complet ce qui n'est pas le cas de MinGW. Ce dernier est un mini système utilisé pour certaines opérations mais pas toutes! En réalité sous Windows le chemin pour arriver à la commande [/bin/mv] correspond à [C:/Program Files/Msys/bin/mv] et MinGW ne s'est pas faire cette correspondance. Donc vous devez utiliser le chemin absolu pour arriver à la commande en question. À cause des espaces blancs dans le chemin, vous devez empaqueter ce chemin dans des doubles quottes: "C:/Program Files/Msys/bin/mv" Sinon vous allez avoir ... C:/Program Le chemin étant perdu après l'espace blanc. Comment faire alors pour avoir un programme qui marche sur les deux systèmes Linux ou Windows (Cygwin ou MinGW)? Nous allons tester l'existence de la variable _WIN32 pour déterminer si nous sommes en présence de Windows ou Linux. Cette variable est définie que sur un poste Windows. Si vous voulez distinguer entre MinGW et Cygwin, vous devez définir aussi une autre variable. Par ailleurs, nous vous proposons deux solutions. Une plus longue mais "simple" à comprendre, et une autre plus rapide. Pour cette dernière la fonction system accepte comme argument un char* La question qui va se poser par elle-même : Comment faire alors pour convertir un string vers un char*? Nous utilisons pour cela la méthode c_str définie dans la classe string. */ #ifndef _SetR_ #define _SetR_ #ifdef _WIN32 #define BINMV "C:/Program Files/Msys/bin/mv" #else #define BINMV "/bin/mv" #endif #include #include #include #include using namespace std; // --------------------------------------------------- // Une classe qui utilise deux fichiers (un in un out) // --------------------------------------------------- class SetR { private: static const int taille_tampon; // taille du buffer tampon char *tampon; // buffer tampon ifstream *entree; // fichier en entrée ofstream *sortie; // fichier en sortie string s; // une string pour les besoins .... string s_in; // le nom du fichier en entrée string s_out; // le nom du fichier en sortie unsigned int i; // Note: le mot inline est ici superflu (car par défaut) // Procédure de recherche et remplacement inline string & Remplace(char *input, char *toReplace, char *by) { s = input; for (i=0; (i=s.find(toReplace,i)) < s.size(); i++) s.replace(i,strlen(toReplace),by); return s; } public: // Constructeur, par défaut nous lui avons passe, la chaîne à chercher // et la chaîne remplaçante. // Cependant on peut modifier ces valeurs, voir le main. SetR(char *fichier,char *toReplace="tempete",char *by="fausse alerte !"); ~SetR(); }; #endif // end _SetR_