Récupérer les différences entre 2 fichiers

Signaler
Messages postés
1
Date d'inscription
lundi 4 janvier 2021
Statut
Membre
Dernière intervention
4 janvier 2021
-
Messages postés
29493
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
8 janvier 2021
-
Bonjour,

Je souhaite récupérer uniquement les différences entre deux fichiers. Je m'explique, prenons :
  • le fichier A, qui contient "12azer45 65test"
  • le fichier B, b qui contient "123azerT45 658858585tTest"

... je voudrais récupérer un fichier qui contient 3T8858585T.

Est ce que cela est possible ?
Je suis ouvert à toute proposition,
D'avance merci

1 réponse

Messages postés
29493
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
8 janvier 2021
7 012
Bonjour,

Le problème que tu résous est un cas particulier du problème de recherche de plus longue sous séquence qui d'un point de vue théorique s'applique caractère par caractère (c'est juste que dans diff, chaque ligne peut être vue comme un "gros" caractère). Sans entrer trop dans les maths, la résolution du programme dynamique sous-jacent permet de déduire quels caractères sont ajoutés et supprimés.

Sous linux, la commande
diff
permet de déterminer les différences entre deux fichiers (ajouts, suppressions, modifications) en traitant ces fichiers ligne par ligne. Tu peux donc t'inspirer de cette discussion mais le raisonnement reste ligne par ligne.

Exemple :

(mando@aldur) (~) $ echo "12azer45 65test" > a.txt
(mando@aldur) (~) $ echo "123azerT45 658858585tTest" > b.txt
(mando@aldur) (~) $ diff <(cat a.txt) <(cat b.txt)
1c1
< 12azer45 65test
---
> 123azerT45 658858585tTest


Donc on va tricher un peu, on transformer le contenu des deux fichiers de sorte à écrire un caractère par ligne, comme expliqué ici.

(mando@aldur) (~) $ diff <(cat a.txt|sed 's/\(.\)/\1\n/g') <(cat b.txt|sed 's/\(.\)/\1\n/g')
2a3
> 3
6a8
> T
11a14,20
> 8
> 8
> 5
> 8
> 5
> 8
> 5
12a22
> T


Comme tu vois, les lignes qui nous intéressent sont celles qui commencent par > (donc on va utiliser
grep "^>"
pour les récupérer), après le premier espace (donc on va utiliser
cut -d" " -f2
).

(mando@aldur) (~) $ diff <(cat a.txt|sed 's/\(.\)/\1\n/g') <(cat b.txt|sed 's/\(.\)/\1\n/g') | grep "^>" | cut -d" " -f2
3
T
8
8
5
8
5
8
5
T


Il ne reste plus qu' à remettre le tout sur une ligne. J'ai essayé comme suggéré ici la commande
xargs
mais elle introduit des espaces.

(mando@aldur) (~) $ diff <(cat a.txt|sed 's/\(.\)/\1\n/g') <(cat b.txt|sed 's/\(.\)/\1\n/g') | grep "^>" | cut -d" " -f2 | xargs
3 T 8 8 5 8 5 8 5 T


Bref peut être que ça te suffit mais le cas échéant tu as au moins une bonne partie qui est faite :-)

Bonne chance
Oui je vois le principe, merci, je vais essayer demain
Messages postés
29493
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
8 janvier 2021
7 012 > Electronis
Parfait, note que sur le principe (en adaptant ton
grep
, tu peux aussi récupérer les suppressions (qui seront préfixées par "< ").

Après si tu es d'humeur à développer, tu peux récupérer une implémentation dans le langage de ton choix qui calcule une LCS. Par exemple, cette page donne une implémentation naïve de calcul de LCS écrite en python. Il s'agit, comme indiqué sur le site, d'une implémentation naïve, car de nombreux travaux de recherche proposent des algorithmes plus performants. Mais bon, tant que tu ne cherches que des "soustractions" et tant que tes fichiers restent courts, tu n'en as sûrement pas le besoin...

Bonne chance