Comparer deux fichiers

Signaler
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
-
boualiasma
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
-
Bonjour,

J'ai deux fichiers "exemple.txt" et "essai.txt"
J'aime afficher les lignes qui existent dans "exemple.txt" et qui n'existent pas dans "essai.txt"
c'est comme une sorte de la différence.

Chaque ligne de fichier contient une chaine de caractère.
Mon idée :
pour chaque ligne de "exemple.txt" je teste si elle existe dans "essai.txt".
Si oui je l'affiche.

Le problème que on peut trouver la même chaine de caractère de "exemple.txt" mais dont l'ordre des mots formant cette chaine est différent de celui dans "essai.txt"

on affiche la chaine autant qui se compose de mêmes mots.

Soit le fichier "exemple.txt"

nom prenom
nom age
nom prenom age
nom emploi
age emploi
prenom age empoi
nom age emploi
nom prenom emploi
nom prenom age emploi


Soit le fichier "essai.txt"

nom
prenom
age
emploi
age nom
nom age prenom
nom emploi
age emploi
prenom age empoi
nom prenom emploi
nom prenom age emploi


le résultat souhaité est:

nom prenom
nom age
nom age emploi


Comment on obtient ce résultat ?

Merci.

108 réponses

Messages postés
6063
Date d'inscription
dimanche 13 avril 2003
Statut
Modérateur
Dernière intervention
15 juillet 2011
25
Salut,

Ton résultat semble faut.

En c#, je chargerai les données dans un hastable
ou un autre type de collections

Et je regarderais si la premiere collection contient l'élément courant.

Apres pour l'ordre il y a plusieurs possibilités.
Tu compares les valeurs des tableaux

par exemple.

Désolé c'est en c# mais les collections existent en C++
alors il reste plus que les algos a faire.

Bon dev.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
bonjour,
Je vous explique ma demande.
Soit le premier fichier fichier "f.txt":
nom prenom
nom age
nom prenom age
nom emploi
age emploi
prenom age emploi
nom age emploi
nom prenom emploi
nom prenom age emploi

Soit le deuxième fichier "f2.txt":

nom
prenom
age
emploi
age nom
nom age prenom
nom emploi
age emploi
prenom age emploi
nom prenom emploi
nom prenom age emploi

votre solution donne:
nom prenom
nom age
nom prenom age

C'est à dire les lignes qui appartiennent à "f.txt" et n'appartiennent pas à "f2.txt"


Mais, moi je cherche les lignes qui appartiennent à "f.txt" et n'appartiennent pas à "f2.txt"
avec les mots de chaque ligne ne sont pas les mêmes
quelque soit l'ordre.

par exemple,
Dans la ligne de "f.txt":
nom age
est le même que dans "f2.txt" :
age emploi

car les deux lignes ont le même ensemble des mots {nom, age}

Donc le résultat ne contient pas la ligne: nom age


de même Dans la ligne de "f.txt":
nom prenom age
est le même que dans "f2.txt" :
nom age prenom


Enfin en se basant sur l'hypothèse que on compare les lignes qui ont les mêmes mots quelque soit l'ordre

Donc on obtient comme résultat:
nom prenom
nom age emploi

Avez-vous une proposition car j'ai trouvé une difficulté de dire deux lignes sont les mêmes avec leurs mots qui forment ces deux lignes dans un ordre différent ?


Merci.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Voici une l'une des méthodes possibles:

- Créer une fonction "bool diffLine(std::vector<std::string> > a, std::vector<std::string> > b)" qui compare deux tableaux de string. Celle-ci tri par ordre alphabétique les deux tableaux, avant de vérifier qu'ils sont identiques.
- Créer une fonction "std::string getLine(std::ifstream file, int pos)" qui récupère une ligne d'un fichier.
- Créer une fonction "std::vector<std::string> > split(std::string s, char delim = " ")" qui découpe les mots d'une ligne en fonction d'un délimiteur.

Enfin applique la méthode suivante:
Pour la premiere a la derniere ligne du premier fichier (ligneCouranteFichier1) faire
  tableau1 = split(ligneCouranteFichier1);
  Pour la premiere a la derniere ligne du deuxieme fichier (ligneCouranteFichier2) faire
    tableau2 = split(ligneCouranteFichier2);
    Si (diffLine(tableau1, tableau2))
      // les lignes sont identiques
    Sinon
      // les lignes sont differentes
    fin si
  fni pour
fin pour


Ce n'est pas la meilleure méthode, ni la plus optimisé. C'est juste une des méthodes possibles. Il y a dans la STL des transformateur intéressants, pense à y jeter un oeil (notamment pour le tri).
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Mon programme est en C.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Oui, et alors ? Je te donne une méthode pour réaliser ce que tu veux. Je ne vais pas le coder à ta place. A toi de l'adapter. Si tu bloques sur un morceau de code, poste ce qui pose problème mais à toi d'essayer de le faire par toi même en t'aidant si tu le désires de la démarche que je viens de décrire dans mon précédent post.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Pour les méthodes du C++, il suffit de les remplacer par du C.

std::string => char*
std::vector<std::string> => char**
std::ifstream => FILE

La méthode reste exactement la même.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Je vous explique ma demande.
Je cherche les lignes qui appartiennent à "f.txt" et non pas "f2.txt"
C'est une sorte de différence lignes de "f.txt" moins lignes de "f2.txt"
à condition:
Une ligne de "f.txt" est identique à une ligne de "f2.txt"
si les deux lignes ont la même valeur et le même nombre des mots qui forment les deux lignes quelque soit l'ordre des mots puisque l'ordre des mots n'est pas important dans mon problème.
le plus important c'est : la même valeur et le même nombre

Sinon c'est à dire les deux lignes n'ont pas la même valeur et le même nombre des mots alors dans ce cas les deux lignes sont différentes.

par exemple:
"nom prenom age" = "nom age prenom"

et donc l'ordre est ignoré.

J'espère que je le problème est clair sinon je vous explique encore.

Sachant que chaque ligne du deux fichiers "f.txt" et "f2.txt" est composé d'un seul champ (une chaine de caractères)
Le remplissage de deux fichiers se fait par:
fprintf(fp,"%s",s);  //le fichier "f.txt"
fprintf(fp2,"%s",s); //le fichier "f2.txt"


Je n'arrive pas à implémenter votre solution

J'ai besoin de vos aides

Merci.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
J'avais bien compris le problème, inutile de le réexpliquer. La méthode que je t'ai donné peut résoudre celui-ci. A toi de commencer à la coder. Je t'ai découpé cette méthode en plusieurs fonctions. Commence déjà par implémenter celles-ci, et poste les morceaux de code qui pourraient poser problème.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Je m'excuse de ma part car le problème est dans l'extension du ficher.
au lieu de lui nommer "f.txt" j'ai le nommer "f.txt.txt".

Effectivement il ne te reste plus qu'à coder "same_word".


J'essaye de coder votre idée mais j'ai trouvé une difficulté de savoir quels sont les paramètres de fonctions citées au dessus et leurs valeurs de retour.

Pouvez vous détailler le code de ces fonctions ?
Je serais très contente pour toute aide.

Merci.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
c:\tester_\debug> tester_.exe f.txt f1.txt

Ceci fonctionne chez moi. Si ça ne fonctionne pas chez toi, tu as du faire une erreur quelque part.

[...] de plus moi je n'utilise pas l'exécution ar ligne de commande car j'utilise l'environnement visual studio 2008 pour la compilation et l'exécution ?


Un IDE (ici Visual Studio) n'a jamais empêché de faire la ligne de commande ! Il y a toujours une option pour le faire.

Pouvez vous posté une version de votre solution sans utiliser argc et argv ?

Quant à poster une version sans argv et argc, je pense que tu as les compétences nécessaires pour le faire tout seul.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Voici une version sans argc et argv.
De plus il y a une boucle pour traiter:
-l'intersection entre f.txt f1.txt
-l'intersection entre f.txt f2.txt
-l'intersection entre f.txt f3.txt

Je connais le nombre de fichiers.
Seulement, j'ai mis N=3 pour voir comment se passe.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_SIZE 1024

char* strndup(const char *str, size_t n)
{

  char *ret = malloc((n+1) * sizeof (char));

  if (!ret)

    exit(0);


  strncpy(ret, str, n);

  ret[n] = 0;

  return ret;

}


void free_tab(char** t)
{

  char** head = t;

  while (t && *t)
  {

    free(*t);
    t++;
  }


  free(head);

}


char** get_word(const char* str)
{

  char* pos = NULL;
  char** res = NULL;
  int nb = 0;

  do
  {
    int size = 0;
    pos = strchr(str, ' ');

    if (pos)

      size = pos - str;


    else

      size = strlen(str) - 1; // - 1 to get rid of \n 

    nb++;

    res = realloc(res, (nb + 1) * sizeof (char*));

    res[nb -1] = strndup(str,  size);

    str = pos + 1;

  }

  while (pos);

  res[nb] = 0;

  return res;
}




int is_same(const char* const s1, const char* const s2)

{

  char **t1, **t2;

  int ret = 0;

  t1 = get_word(s1);

  t2 = get_word(s2);


  if (t1 && t2)
 {

    char** tab1 = t1;

    char** tab2 = t2;

    int nb = 0;

    int size = 0;

    while (tab1 && *tab1)

    {

      tab2 = t2;

      while (tab2 && *tab2)
      {

if (!strcmp(*tab1, *tab2))

  nb++;

tab2++;

      }


      tab1++;

      size++;

    }



    ret = (nb >= size);

    free_tab(t1);

    free_tab(t2);


  }

  return ret;

}



char** compare_file(const char* filename1, const char* filename2)
{

  FILE *f, *f1;

  char s[MAX_SIZE], s1[MAX_SIZE];

  int a;

  char** res = NULL;

  int nb = 0;

  f = fopen(filename1, "r");

  f1 = fopen(filename2, "r");

  if (f && f1)

  {

    while (fgets(s, MAX_SIZE, f))

    {

      a = 0;

      rewind(f1);

      while (fgets(s1, MAX_SIZE, f1))

      {

if (is_same(s, s1))

{

  a = 1;

  break;

}

      }

      if (!a)
      {

nb++;

res = realloc(res, (nb + 1) * sizeof (char*));

res[nb - 1] = strndup(s, strlen(s) - 1); //* Get rid of the \n 

res[nb] = 0;

      }

    }

    fclose(f);

    fclose(f1);

 }


printf("nb ret=%d\n", nb);


 return res;

}


int main()
{

  char** res = NULL;

  char** pos = NULL;

  char input[32];

  int i ;

 
  for (i 1; i <3; i++)

  {

    sprintf(input,"f%d.txt",i);

    res = compare_file("f.txt",input);

    pos = res;

    printf("Comparing f.txt and %s:\n", input);

    while (pos && *pos)

    {

      printf("%s\n", *pos);

     pos++;

    }

    free_tab(res);

  }



  return 0;

}



La compilation se passe bien mais après l'exécution il y a des affichages ne s'affichent pas et surtout après la fonction "compare_file"

J'ai besoin de votre aide car le résultat final de ce problème n'est pas encore atteinte.

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Voici un exemple:

Soit le premier fichier fichier "f.txt":
nom prenom
nom age
nom prenom age
nom emploi
age emploi
prenom age emploi
nom age emploi
nom prenom emploi
nom prenom age emploi

Soit le deuxième fichier "f2.txt":

nom
prenom
age
emploi
age nom
nom age prenom
nom emploi
age emploi
prenom age emploi
nom prenom emploi
nom prenom age emploi

Le résultat souhaité:
nom prenom
nom age emploi
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Inutile de réecrire à chaque fois le principe. A TOI de coder le truc en C. Si tu bloques, nous t'aiderons, mais personne ne le codera pour toi.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Voici un premier essai:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{

FILE *f,*f2 ;
char s[1000], s2[1000];

f = fopen("f.txt", "r");
f2 = fopen("f2.txt", "r");
while(fgets(s, 1000, f)!= NULL)
{
 
   rewind(f2);
   while(fgets(s2, 1000, f2)!= NULL)
      if(strcmp(s, s2))
             printf("%s\n",s);
         
   }
fclose(f);
fclose(f2);
return 0;
}


Mais cette solution tient de l'ordre des mots de deux lignes pour chaque fichier.
"nom prenom age" est différent " nom age prenom"

j'ai dit il suffit de changer cette condition: if(!strcmp(s, s2)) par un truc comme if(same_word(s, s2)) .
mais, je trouve difficulté de implémenter
la fonction same_word(s, s2)

Comment je vais modifier cette solution pour ignorer l'ordre.
pour obtenir:

"nom prenom age" = " nom age prenom"

Merci.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Effectivement il ne te reste plus qu'à coder "same_word".

Pour ceci, il suffit de découper ta fonction en une série de fonction. Essaie de coder ceci:
- char** split(char* str, delim d = " "); Qui va découper une chaîné de caractère en fonction d'un délimiteur. (Aide toi de la fonction strstr qui est dans string.h).
Ex: "nom prenom age" => un tableau contenant {"nom", "prenom", "age"}
- Ecrit une fonction qui trie les tableaux par ordre alphabétique: void sort(char** tab);
- Ensuite écrit une fonction int cmp_tab(char** tab1, char** tab2), qui va comparer les tableaux entre eux, en les triant au préalable à l'aide la fonction sort faites avant.
- Enfin same_words consiste juste à utiliser toutes les méthodes codées précédemment. Essaie de les coder dans cette ordre.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
J'ai testé le code suivant :


  #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
  
    int main()
    {
      8. FILE *f,*f2 ;
    char s[1000], s2[1000];
  
  f = fopen("f.txt", "r" );
   f2 = fopen("f2.txt", "r" );
   while(fgets(s, 1000, f)!= NULL)
   {
  
      rewind(f2);
      while(fgets(s2, 1000, f2)!= NULL)
         if(strcmp(s, s2))
                printf("%s\n",s);
          
      }
  fclose(f);
   fclose(f2);
  return 0;

}


La compilation se passe bien. Mais, l'exécution ne passe pas bien puisque il y a une génération de l'exception suivante:

Debug assertion Failed!
Prpgram :
File : f\dd\vctools\crt_bld\self_x86\crt\src\fgets.c
Line : 57

Expression : (str != NULL)



D'où vient cette erreur ?

Merci.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Tu dois simplement tester si l'ouverture du fichier a réussi ou non.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  FILE *f, *f2;
  char s[1000], s2[1000];
  char* filename1 = "f.txt";
  char* filename2 = "f2.txt";

  f = fopen(filename1, "r" );
  if (f == NULL)
  {
    printf("Unable to open file %s\n", filename1);
    return 1;
  }

  f2 = fopen(filename2, "r" );
  if (f2 == NULL)
  {
    printf("Unable to open file %s\n", filename2);
    return 1;
  }

  while (fgets(s, 1000, f) != NULL)
  {
    rewind(f2);
    while (fgets(s2, 1000, f2) != NULL)
      if (strcmp(s, s2))
printf("%s\n",s);
  }
  fclose(f);
  fclose(f2);

  return 0;
}
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Après l'exécution, il m'affiche :

Unable to open file f

Mais, les deux fichiers existent.
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Ton fichier n'est pas trouvé, tout simplement. Vérifie le chemin. Et regarde si le repertoire de travail est correcte.
Met un chemin absolu, au pire du genre "/home//f.txt" (unix), ou "C:\\f.txt" (windows)
Messages postés
3805
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 mars 2020
98
Tu peux aussi utiliser "perror" pour voir l'erreur précise retournée:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  FILE *f, *f2;
  char s[1000], s2[1000];
  char* filename1 = "z.txt";
  char* filename2 = "z2.txt";

  f = fopen(filename1, "r" );
  if (f == NULL)
  {
    perror(filename1);
    return 1;
  }

  f2 = fopen(filename2, "r" );
  if (f2 == NULL)
  {
    perror(filename1);
g    return 1;
  }

  while (fgets(s, 1000, f) != NULL)
  {
    rewind(f2);
    while (fgets(s2, 1000, f2) != NULL)
      if (strcmp(s, s2))
printf("%s\n",s);
  }
  fclose(f);
  fclose(f2);

  return 0;
}
1 2 3 4 5 6