#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define OUTPUT_NAME "finalresult.txt" /* Nom du fichier dans lequel le resultat est stocké */ #define MAX_SIZE 1024 /* Taille maximale d'une ligne du fichier */ /** Teste le retour de realloc et quitte le programme si besoin */ void * xrealloc(void * prec, size_t len) { void *ret = realloc(prec, len); if(!ret) /* Equivaut à if(ret == NULL) */ exit(0xDEAD); return ret; } /** Copie n caractère de str dans une nouvelle chaine alloué dynamiquement, et renvoie cette chaine */ char * mstrndup(const char *str, size_t n) { char *ret = malloc((n+1) * sizeof(char)); if (!ret) exit(0xDEAD); strncpy(ret, str, n); /* Copie n caractère de str dans n */ ret[n] = 0; /* 0 == '\0' */ return ret; } /** Libère le tableau de chaine de caractère t de len chaine de caractère */ void free_tab(char **t, size_t len) { if (t) { size_t i; for (i = 0; i < len; i++) free(t[i]); free(t); } } /** Libère le tableau de chaine de caractère t et s'arrête lorsqu'un pointeur NULL est rencontré */ void free_tab2(char **t) { size_t i = 0; while (t && t[i]) free(t[i++]); free(t); } /** Compte le nombre de mot dans str (un mot correspond à une suite de lettre et s'arrête dès qu'un caractère autre est rencontré */ size_t count_word(const char *str) { size_t n = 0; int a; while (*str) /* Equivaut à while(*str != '\0') */ { a = 0; /* Cette variable sert à indiquer si au moins une lettre a été trouvé (pour éviter les lignes vides) */ while (isalpha((unsigned char) *str) && *str) str++, a = 1; /* Tant que c'est une lettre et que ce n'est pas la fin de la chaine, on parcourt la chaine et on met a à 1 pour indiquer qu'on a trouvé au moins une lettre */ if (a) n++; /* Si on a trouvé au moins une lettre, on augmente le nombre de mot */ while (!isalpha((unsigned char) *str) && *str) str++; /* On saute tous les caractères qui ne sont pas des lettres */ } return n; } /** copie les mots de la chaine str dans le tableau de chaine de caractère tab */ void get_word(char **tab, const char *str) { const char* p = str; int a, i = 0; /* Le fonctionnement est le même que pour la fonction count_word mais ici on enregistre la chaien dans un tableau. On pourrait le faire en une seule fonction mais il faudrai à chaque fois réallouer de la mémoire et ce n'est pas très propre */ while (*str) { a = 0; while (isalpha((unsigned char) *p) && *p) p++, a = 1; if (a) tab[i++] = mstrndup(str, p-str); /* Si on a trouvé un mot, on met dans tab[i] le mot (la suite de lettre trouvé) et on incrémente i. p-str correspond à la taille du mot, c'est l'adresse du caractère suivant le dernier caractère moins l'adresse du premier caractère */ while (!isalpha((unsigned char) *p) && *p) p++; str = p; } } /** Compare deux tableaux de mots, renvoie 1 si ces tableaux sont identiques sans tenir compte de l'ordre ni du nombre de mot, 0 sinon (En fait, il renvoie 1 si chaque ligne de t1 existe dans t2) */ int compareline(char **t1, size_t size1, char **t2, size_t size2) { int ret = 1; size_t i, j; int a; /* Pour chaque ligne de t1, on compare avec chaque ligne de t2. Si à un moment on ne trouve pas la ligne, alors les tableaux ne sont pas identiques */ for (i = 0; i < size1; i++) { a = 0; for (j = 0; j < size2; j++) if (!strcmp(t1[i], t2[j])) { a = 1; break; /* Dès que la ligne est trouvé, on peux arrêter de comparer pour cette valeur du tableau */ } if (!a) { ret = 0; break; /* Dès qu'une ligne manque, on peux arrêter la comparaison */ } } return ret; } /** Compare deux chaines de caractère, si comparesize vaut 1 alors la première doit contenir la seconde, et renvoie 1 si elles sont identiques sans tenir compte de l'ordre des mots */ int is_same(const char *s1, const char *s2, int comparesize) { char **t1, **t2; size_t size1 count_word(s1), size2 count_word(s2); int ret = 0; if (!comparesize || (size1 > size2)) /* Si comparesize vaut 0, on ne compare pas la taille, si comparesize vaut 1 alors il faut que size1 > size 2 */ { t1 = malloc(size1 * sizeof(char*)); t2 = malloc(size2 * sizeof(char*)); if (t1 && t2) { get_word(t1, s1); get_word(t2, s2); ret = comparesize? compareline(t2, size2, t1, size1) : compareline(t1, size1, t2, size2); free_tab(t1, size1), free_tab(t2, size2); } else exit(0xDEAD); } return ret; } /** Compare deux fichiers er renvoie le résultat de la comparaison */ char ** compare_files(const char *filename1, const char *filename2) { FILE *f fopen(filename1, "r"), *f2 fopen(filename2, "r"); char s[MAX_SIZE], s2[MAX_SIZE]; int a, retsize = 0; char **ret = NULL; if (f && f2) /* Si les fichiers sont bien ouverts */ { while (fgets(s, MAX_SIZE, f)) /* C'est la même principe que dans la fonction compareline en fait */ { a = 0; rewind(f2); while (fgets(s2, MAX_SIZE, f2)) if (is_same(s, s2, 0)) { a = 1; break; } if (!a) { ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On alloue une case de plus au tableau de string, puis on ajoute la chaine à la fin du tableau */ ret[retsize-1] = mstrndup(s, strlen(s)); } } fclose(f), fclose(f2); ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On ajoute un dernier pointeur sur NULL pour savoir quand le tableau se termine */ ret[retsize-1] = NULL; } else /* Si un fichier n'a pas pu être ouvert, on ferme eventuellement le fichier qui a pu être ouvert */ { if (f) fclose(f); if (f2) fclose(f2); } return ret; } /** Ecrit le tableau de len chaines de caractère dans le flux f */ void write_tab(FILE *f, char **t, size_t len) { size_t i; for (i = 0; t && i < len; i++) if (t[i]) fprintf(f, t[i]); } int main(void) { #define MAXFILE 3 /* Le nombre de fichier à comparer, on compare f.txt à f1.txt, f2.txt etc... */ #define MAXTMP 10 /* La taille maximum du nom de fichier */ char **rets[MAXFILE] = {NULL}, tmp[MAXTMP]; char **interret = NULL; size_t interret_size = 0; int i,j,k; int a, b; FILE *output; for (i = 0; i < MAXFILE; i++) /* Pour chaque fichier */ { sprintf(tmp, "f%d.txt", i+1); rets[i] = compare_files("f.txt", tmp); /* On comparer f.txt avec f%d.txt où %d est un nombre de 1 à MAXFILE */ } i = 0; while (rets[0] && rets[0][i]) /* Tant que ça ne vaut pas NULL */ { a b 0; for (j = 1; j < MAXFILE; j++) /* On compare le premier avec tous les autres */ { k = 0; while (rets[j] && rets[j][k]) /* On parcourt le tableau en entier (je rappelle qu'il est terminé par NULL */ { if (!strcmp(rets[0][i], rets[j][k])) /* Si on trouve une ligne identique */ { a = 1; /* On met a à 1, c'est à dire que la ligne rets[0][i] existe dans ret[j] */ break; } k++; } if (!a) /* Si on a pas trouvé la ligne, alors on met b à 1, ça veux dire que la ligne du tableau n'existe pas dans tous les autres tableaux */ { b = 1; break; } } if (!b) /* Si b vaut 0 (on a trouvé la ligne ret[0][i] dans tous les tableaux ret[j] avec 0 < j < MAXFILE) */ { interret = xrealloc(interret, (++interret_size) * sizeof(char*)); interret[interret_size-1] = mstrndup(rets[0][i], strlen(rets[0][i])); /* On recopie la ligne dans un nouveau tableau */ } i++; } for (i = 0; i < MAXFILE; i++) /* On nettoie les tableaux issus des comparaison maistenant que l'intersection a été faite */ free_tab2(rets[i]); for (i = 0; i < interret_size; i++) /* Pour chaque case du tableau... */ { for (j = 0; interret[i] && j < interret_size; j++) /* On compare avec toutes les cases tant que la case actuelle ne vaut pas NULL */ { if (interret[j] && j != i) /* Si la case qu'on veux comparer ne vaut pas NULL et que i est différent de j (sinon on compare la même case!) */ if (is_same(interret[i], interret[j], 1)) /* Si interret[j] est inclu dans interret[i] */ { free(interret[i]), interret[i] = NULL; /* On supprime la case */ break; } } } if((output = fopen(OUTPUT_NAME, "w+")) != NULL) /* On ouvre le fichier et on écrit le résultat si le fichier a bien été ouvert */ { write_tab(output, interret, interret_size); fclose(output); } free_tab(interret, interret_size); /* On nettoie le dernier tableau */ return 0; }
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questiona b
a c
a d
b c
b d
c d
a b c
a b d
b c d
a c d
a b c d
a b
a c
a d
b c
b d
c d
a b c
a b d
b c d
a c d
a
c
b
d
b a
d a
b c
d c
b c a
a
b
c
c a
d a
b a
b c
b c a
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define OUTPUT_NAME "finalresult.txt" /* Nom du fichier dans lequel le resultat est stocké */ #define MAX_SIZE 1024 /* Taille maximale d'une ligne du fichier */ /** Teste le retour de realloc et quitte le programme si besoin */ void * xrealloc(void * prec, size_t len) { void *ret = realloc(prec, len); if(!ret) /* Equivaut à if(ret == NULL) */ exit(0xDEAD); return ret; } /** Copie n caractère de str dans une nouvelle chaine alloué dynamiquement, et renvoie cette chaine */ char * mstrndup(const char *str, size_t n) { char *ret = malloc((n+1) * sizeof(char)); if (!ret) exit(0xDEAD); strncpy(ret, str, n); /* Copie n caractère de str dans n */ ret[n] = 0; /* 0 == '\0' */ return ret; } /** Libère le tableau de chaine de caractère t de len chaine de caractère */ void free_tab(char **t, size_t len) { if (t) { size_t i; for (i = 0; i < len; i++) free(t[i]); free(t); } } /** Libère le tableau de chaine de caractère t et s'arrête lorsqu'un pointeur NULL est rencontré */ void free_tab2(char **t) { size_t i = 0; while (t && t[i]) free(t[i++]); free(t); } /** Compte le nombre de mot dans str (un mot correspond à une suite de lettre et s'arrête dès qu'un caractère autre est rencontré */ size_t count_word(const char *str) { size_t n = 0; int a; while (*str) /* Equivaut à while(*str != '\0') */ { a = 0; /* Cette variable sert à indiquer si au moins une lettre a été trouvé (pour éviter les lignes vides) */ while (isalpha((unsigned char) *str) && *str) str++, a = 1; /* Tant que c'est une lettre et que ce n'est pas la fin de la chaine, on parcourt la chaine et on met a à 1 pour indiquer qu'on a trouvé au moins une lettre */ if (a) n++; /* Si on a trouvé au moins une lettre, on augmente le nombre de mot */ while (!isalpha((unsigned char) *str) && *str) str++; /* On saute tous les caractères qui ne sont pas des lettres */ } return n; } /** copie les mots de la chaine str dans le tableau de chaine de caractère tab */ void get_word(char **tab, const char *str) { const char* p = str; int a, i = 0; /* Le fonctionnement est le même que pour la fonction count_word mais ici on enregistre la chaien dans un tableau. On pourrait le faire en une seule fonction mais il faudrai à chaque fois réallouer de la mémoire et ce n'est pas très propre */ while (*str) { a = 0; while (isalpha((unsigned char) *p) && *p) p++, a = 1; if (a) tab[i++] = mstrndup(str, p-str); /* Si on a trouvé un mot, on met dans tab[i] le mot (la suite de lettre trouvé) et on incrémente i. p-str correspond à la taille du mot, c'est l'adresse du caractère suivant le dernier caractère moins l'adresse du premier caractère */ while (!isalpha((unsigned char) *p) && *p) p++; str = p; } } /** Compare deux tableaux de mots, renvoie 1 si ces tableaux sont identiques sans tenir compte de l'ordre ni du nombre de mot, 0 sinon (En fait, il renvoie 1 si chaque ligne de t1 existe dans t2) */ int compareline(char **t1, size_t size1, char **t2, size_t size2) { int ret = 1; size_t i, j; int a; /* Pour chaque ligne de t1, on compare avec chaque ligne de t2. Si à un moment on ne trouve pas la ligne, alors les tableaux ne sont pas identiques */ for (i = 0; i < size1; i++) { a = 0; for (j = 0; j < size2; j++) if (!strcmp(t1[i], t2[j])) { a = 1; break; /* Dès que la ligne est trouvé, on peux arrêter de comparer pour cette valeur du tableau */ } if (!a) { ret = 0; break; /* Dès qu'une ligne manque, on peux arrêter la comparaison */ } } return ret; } /** Compare deux chaines de caractère, si comparesize vaut 1 alors la première doit contenir la seconde, et renvoie 1 si elles sont identiques sans tenir compte de l'ordre des mots */ int is_same(const char *s1, const char *s2, int comparesize) { char **t1, **t2; size_t size1 count_word(s1), size2 count_word(s2); int ret = 0; if (!comparesize || (size1 > size2)) /* Si comparesize vaut 0, on ne compare pas la taille, si comparesize vaut 1 alors il faut que size1 > size 2 */ { t1 = malloc(size1 * sizeof(char*)); t2 = malloc(size2 * sizeof(char*)); if (t1 && t2) { get_word(t1, s1); get_word(t2, s2); ret = comparesize? compareline(t2, size2, t1, size1) : compareline(t1, size1, t2, size2); free_tab(t1, size1), free_tab(t2, size2); } else exit(0xDEAD); } return ret; } /** Compare deux fichiers er renvoie le résultat de la comparaison */ char ** compare_files(const char *filename1, const char *filename2) { FILE *f fopen(filename1, "r"), *f2 fopen(filename2, "r"); char s[MAX_SIZE], s2[MAX_SIZE]; int a, retsize = 0; char **ret = NULL; if (f && f2) /* Si les fichiers sont bien ouverts */ { while (fgets(s, MAX_SIZE, f)) /* C'est la même principe que dans la fonction compareline en fait */ { a = 0; rewind(f2); while (fgets(s2, MAX_SIZE, f2)) if (is_same(s, s2, 0)) { a = 1; break; } if (!a) { ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On alloue une case de plus au tableau de string, puis on ajoute la chaine à la fin du tableau */ ret[retsize-1] = mstrndup(s, strlen(s)); } } fclose(f), fclose(f2); ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On ajoute un dernier pointeur sur NULL pour savoir quand le tableau se termine */ ret[retsize-1] = NULL; } else /* Si un fichier n'a pas pu être ouvert, on ferme eventuellement le fichier qui a pu être ouvert */ { if (f) fclose(f); if (f2) fclose(f2); } return ret; } /** Ecrit le tableau de len chaines de caractère dans le flux f */ void write_tab(FILE *f, char **t, size_t len) { size_t i; for (i = 0; t && i < len; i++) if (t[i]) fprintf(f, t[i]); } int main(void) { #define MAXFILE 3 /* Le nombre de fichier à comparer, on compare f.txt à f1.txt, f2.txt etc... */ #define MAXTMP 10 /* La taille maximum du nom de fichier */ char **rets[MAXFILE] = {NULL}, tmp[MAXTMP]; char **interret = NULL; size_t interret_size = 0,n; int i,j,k; int a, b; FILE *output; rets[0] = compare_files("f.txt","f1.txt"); printf("%s",*rets[0]); n = count_word((*rets[0])); if (n == 4) { printf(" \nNous avons une seule comparaison \n"); if((output = fopen(OUTPUT_NAME, "w+")) != NULL) /* On ouvre le fichier et on écrit le résultat si le fichier a bien été ouvert */ { write_tab(output, rets, n); fclose(output); } } else { printf(" \nNous avons toutes les comparaison \n"); for (i = 1; i < MAXFILE; i++) /* Pour chaque fichier */ { sprintf(tmp, "f%d.txt", i+1); rets[i] = compare_files("f.txt", tmp); /* On comparer f.txt avec f%d.txt où %d est un nombre de 1 à MAXFILE */ } i = 0; while (rets[0] && rets[0][i]) /* Tant que ça ne vaut pas NULL */ { a b 0; for (j = 1; j < MAXFILE; j++) /* On compare le premier avec tous les autres */ { k = 0; while (rets[j] && rets[j][k]) /* On parcourt le tableau en entier (je rappelle qu'il est terminé par NULL */ { if (!strcmp(rets[0][i], rets[j][k])) /* Si on trouve une ligne identique */ { a = 1; /* On met a à 1, c'est à dire que la ligne rets[0][i] existe dans ret[j] */ break; } k++; } if (!a) /* Si on a pas trouvé la ligne, alors on met b à 1, ça veux dire que la ligne du tableau n'existe pas dans tous les autres tableaux */ { b = 1; break; } } if (!b) /* Si b vaut 0 (on a trouvé la ligne ret[0][i] dans tous les tableaux ret[j] avec 0 < j < MAXFILE) */ { interret = xrealloc(interret, (++interret_size) * sizeof(char*)); interret[interret_size-1] = mstrndup(rets[0][i], strlen(rets[0][i])); /* On recopie la ligne dans un nouveau tableau */ } i++; } for (i = 0; i < MAXFILE; i++) /* On nettoie les tableaux issus des comparaison maistenant que l'intersection a été faite */ free_tab2(rets[i]); for (i = 0; i < interret_size; i++) /* Pour chaque case du tableau... */ { for (j = 0; interret[i] && j < interret_size; j++) /* On compare avec toutes les cases tant que la case actuelle ne vaut pas NULL */ { if (interret[j] && j != i) /* Si la case qu'on veux comparer ne vaut pas NULL et que i est différent de j (sinon on compare la même case!) */ if (is_same(interret[i], interret[j], 1)) /* Si interret[j] est inclu dans interret[i] */ { free(interret[i]), interret[i] = NULL; /* On supprime la case */ break; } } } if((output = fopen(OUTPUT_NAME, "w+")) != NULL) /* On ouvre le fichier et on écrit le résultat si le fichier a bien été ouvert */ { write_tab(output, interret, interret_size); fclose(output); } free_tab(interret, interret_size); /* On nettoie le dernier tableau */ } return 0; }