salut tous
je cherche a Supprimer les lignes en double d'un fichier texte (csv)
exemple
1;aaa;0;1;
1;aaa;0;1;
0;aaa;1;0;
1;aaa;0;1;
1;bbb;0;1;
0;aaa;1;0;
1;aaa;0;1;
1;bbb;0;1;
et merci
salut tous
je cherche a Supprimer les lignes en double d'un fichier texte (csv)
exemple
1;aaa;0;1;
1;aaa;0;1;
0;aaa;1;0;
1;aaa;0;1;
1;bbb;0;1;
0;aaa;1;0;
1;aaa;0;1;
1;bbb;0;1;
et merci
Bonjour.
Pour résoudre ce type de problème il faut se poser une première question et surtout y répondre avant de se lancer :
- Le fichier traité pourra-t-il avoir une taille importante?
En fonction de la réponse on aura déjà une première approche :
- OUI : la recherche de doublons ne pourra se faire qu'en lisant le fichier directement sur le disque,
- NON : on pourra charger complètement le fichier en mémoire pour traitement.
Ensuite, comment écrire le fichier ? On continue sur la même lancée :
- Si le fichier est important (donc pas en mémoire) on créera un fichier temporaire qui correspondra au fichier final. Une fois terminé on efface l'original et on le remplace par le temporaire,
- Si le fichier original est chargé en mémoire on crée le fichier final toujours en mémoire. On écrasera au final l'original avec.
Utilisation de Glade avec Gtk+
Code::Blocks et Gtk+ sous Windows
Programmation orientée objet avec Gtk+ v3
- N'oubliez pas de consulter les FAQ Gtk et les cours et tutoriels Gtk
J'ai une autre question importante qui me vient à l'esprit.
- à partir de quelle taille peut-on dire qu'un fichier est de taille importante?
Oui en effet on peut se la poser.
Pour ma part j'y réponds comme ca. Si je développe une application qui traite un fichier dont je ne connais absolument pas la variation de taille je considère dés le départ qu'il sera important.
Ca me rappelle un bogue de Word 2.0 il y a quelques années (voir ce lien) où il était impossible d'enregistrer des fichiers trop volumineux. Les développeurs n'avaient pas anticiper ce type d'utilisation.
Utilisation de Glade avec Gtk+
Code::Blocks et Gtk+ sous Windows
Programmation orientée objet avec Gtk+ v3
- N'oubliez pas de consulter les FAQ Gtk et les cours et tutoriels Gtk
La première question à se poser, à mon avis, est « faut-il supprimer tous les doublons ou uniquement les lignes consécutives » ? Parce que, dans ce dernier cas, l'opération est nettement plus facile à réaliser.
Est-ce que c'est un exercice scolaire à réaliser impérativement en C ou cherches-tu réellement à supprimer les doublons d'un fichier ? Parce que dans ce dernier cas, si tu travailles sous Unix, il y a sort et uniq pour faire ça facilement depuis le shell (c'est un cas de figure très fréquent).
Oui mais autant partir du principe du "Qui peut le plus, peut le moins"La première question à se poser, à mon avis, est « faut-il supprimer tous les doublons ou uniquement les lignes consécutives » ? Parce que, dans ce dernier cas, l'opération est nettement plus facile à réaliser.
Ta première solution (difficile) permet de gérer les lignes consécutives, alors que dans le cas inverse, on est chocolat
Dans un langage de script, c'est effectivement plus simple, mais ce genre d'exercice en C m'intéresse, je me vois bien le tenter afin de progresserEst-ce que c'est un exercice scolaire à réaliser impérativement en C ou cherches-tu réellement à supprimer les doublons d'un fichier ? Parce que dans ce dernier cas, si tu travailles sous Unix, il y a sort et uniq pour faire ça facilement depuis le shell (c'est un cas de figure très fréquent).![]()
Alors la question que l'on doit aussi se poser est si l'opération doit être stable ou non. L'ordre des éléments a-t-il une importance ? Si la première occurence d'une ligne dans le fichier d'origine apparaît avant une autre ligne, cela doit-il aussi être le cas dans le fichier amaigri ?
Oui mais justement : les deux approches sont très différentes en matière de complexité. Donc soit c'est un exercice scolaire et, dans ce cas, il faut être très clair sur ce que veut le prof' parce que l'objectif à court terme n'est probablement pas de réécrire un monument tout de suite, soit c'est un réel cas de figure et dans ce cas, ce n'est pas la peine d'embarquer le primo-postant dans quelque chose qui n'est pas son objectif final.
Mais surtout : il y a une grande différence entre éliminer les répétitions consécutives d'une même ligne et supprimer toutes ses occurrences au sein d'un fichier. L'exemple-type est le fichier de log : si on a n fois le même message, on peut le factoriser. Par contre, si on a un message « x » puis un message « y » puis à nouveau un message « x », alors l'ordre d'apparition de ses messages a une importance ! Et c'est probablement le cas aussi du fichier *.csv du primo-postant. Et ce n'est même pas seulement une question de stabilité de tri dans ce cas : le fait d'avoir reçu un message différent implique la réapparition légitime du premier message dans le fichier de sortie.
Et comme, enfin, la suppression globale des lignes redondantes implique forcément un tri, alors l'approche du shell UNIX est la meilleure : faire d'un côté un outil de tri, de l'autre côté un outil (trivial) de suppression des lignes consécutives, avec possibilité de combiner les deux pour arriver à ses fins.
@obsidian
En effet c'est complexe, du coup je m'en suis fais un défi, je trouve cet exercice intéressant question apprentissage.
Je présente mon code, il est loin d'être parfait, les exceptions ne sont pas encore tapées, mais il est fonctionnel.
J'ai un seul soucis que je ne suis pas sûr pouvoir résoudre, je lis le texte d'un fichier à l'aide de gedit, et j'ai un résultat pas très lisible
Qui n'est bien sûr pas le résultat attendu !!!Bonjour
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00!\00\00\00\00\00\00\00Coucou
\00\00\00\00\00\00\00\00\00Coucou
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00!\00\00\00\00\00\00\00Salut
\00\00\00\00Salut
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00!\00\00\00\00\00\00\00HellHello
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00!\00\00\00\00\00\00\00Bye
Bye
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00Tchao
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00
Voici mon code
test.c
test.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 #include <stdio.h> #include <stdlib.h> #include <string.h> #include "test.h" #define MAX 80 void ajouter(tab *tableau, char *ligne) { tableau->table[tableau->len] = malloc((strlen(ligne)+1) * sizeof(char)); strcpy(tableau->table[tableau->len], ligne); /* copie de ligne dans la liste */ tableau->len++; /* la longueur de la liste augmente de 1 */ } void afficher(tab *tableau) { int i=0; for(; i<tableau->len; i++) { printf("ligne %d --> %s\n", i+1, tableau->table[i]); } } int rechercher(tab *tableau, char *ligne) { int i=0; if (tableau == NULL || tableau->table == NULL) { puts("Pas de doublons dans le fichier"); exit(1); } for(; i<tableau->len; i++) { if (strcmp(tableau->table[i], ligne) == 0) return 1; /* Pour chaque chaine de la liste, je compare à la ligne, si doublon on retourne 1 */ } return 0; /* sinon 0 */ } void lire(FILE *fic, tab *tableau) { char line[MAX]; if (fic == NULL) { puts("Erreur de lecture du fichier\n"); exit(1); } while (fgets(line, MAX, fic) != NULL) /* Tant que pas la fin du fichier je lis la ligne suivante */ { if (rechercher(tableau, line) == 0) ajouter(tableau, line); /* Si pas de doublon, j'ajoute la chaine dans la liste */ } } void ecrire(tab *tableau, FILE *fic) /* Ecriture des éléments de la liste dans le fichier fic */ { int i=0, n=0; char *element; if (fic == NULL) { puts("Erreur lors de l'écriture\n"); exit(1); } for(; i<tableau->len; i++) { element = tableau->table[i]; n = strlen(element); fwrite(element, n * sizeof(element), 1, fic); } } tab *creer() { tab *new = malloc(sizeof(tab)); /* On alloue de la mémoire pour le nouveau tableau */ new->table = malloc(MAX * sizeof(char)); /* On alloue pour la chaine dont on ne connait pas sa longueur */ new->len = 0; /* Longueur nulle à la création */ if (new == NULL || new->table == NULL) { puts("Erreur d'allocation mémoire"); exit(1); } return new; /* On retourne la liste vide */ } void detruire(tab *tableau) { int i; if (tableau != NULL) { for(i=0; i<0; i++) { free(tableau->table[i]); /* nettoyage de chacun des éléments */ } free(tableau->table); free(tableau); } } int main(void) { tab *T = creer(); FILE *fichier; FILE *fichier_temp; fichier = fopen("/home/fred1599/Desktop/test.txt", "r"); fichier_temp = fopen("/home/fred1599/Desktop/test_temp.txt", "w"); lire(fichier, T); afficher(T); ecrire(T, fichier_temp); detruire(T); return 0; }
Bref c'était chaud, je suis un peu naze, du coup j'ai pu passer à côté de quelque chose...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #ifndef TEST_H_INCLUDED #define TEST_H_INCLUDED typedef struct { char **table; int len; } tab; void ajouter(tab *tableau, char *ligne); void afficher(tab *tableau); tab *creer(); int rechercher(tab *tableau, char *ligne); void ecrire(tab *tableau, FILE *fic); void lire(FILE *fic, tab *tableau); void detruire(tab *tableau); #endif
Je crois ne pas avoir bien compris la fonction fwrite (doute)
Edit : J'ai fais une modification dans la fonction écrire.
Edit 2 : Quelques exceptions de rajouter
Edit 3 : Fonction nommée creer() au lieu de create() et modif fonction affichage()
Edit 4 : Rajout de commentaires
Merci par avance,
Partager