Question

Je cherchais à faire quelque chose comme ce que je crois les systèmes de contrôle des changements font, ils comparent deux fichiers, et enregistrer une petite diff chaque fois que les modifications de fichiers. J'ai lu cette page: http://docs.python.org/library/difflib.html et il ne s'enfoncer dans la tête à mon apparence.

Je tente de recréer cela dans un programme assez simple illustré ci-dessous, mais la chose que je semble manquer est que les contiennent du Delta au moins autant que le fichier original, et plus encore.

est-il pas possible d'arriver à seulement les changements purs? La raison pour laquelle je demande est, espérons évident - pour économiser l'espace disque
. Je pouvais sauver tout le morceau de code à chaque fois, mais il serait préférable de sauver code actuel une fois, puis les petites diffs des changements.

Je suis aussi toujours essayer de comprendre pourquoi de nombreuses fonctions difflib retourne un générateur au lieu d'une liste, quel est l'avantage là-bas?

Will travail difflib pour moi - ou je dois trouver un paquet plus professionnel avec plus de fonctionnalités?

# Python Difflib demo 
# Author: Neal Walters 
# loosely based on http://ahlawat.net/wordpress/?p=371
# 01/17/2011 

# build the files here - later we will just read the files probably 
file1Contents="""
for j = 1 to 10: 
   print "ABC"
   print "DEF" 
   print "HIJ"
   print "JKL"
   print "Hello World"
   print "j=" + j 
   print "XYZ"
"""

file2Contents = """
for j = 1 to 10: 
   print "ABC"
   print "DEF" 
   print "HIJ"
   print "JKL"
   print "Hello World"
   print "XYZ"
print "The end"
"""

filename1 = "diff_file1.txt" 
filename2 = "diff_file2.txt" 

file1 = open(filename1,"w") 
file2 = open(filename2,"w") 

file1.write(file1Contents) 
file2.write(file2Contents) 

file1.close()
file2.close() 
#end of file build 

lines1 = open(filename1, "r").readlines()
lines2 = open(filename2, "r").readlines()

import difflib

print "\n FILE 1 \n" 
for line in lines1:
  print line 

print "\n FILE 2 \n" 
for line in lines2: 
  print line 

diffSequence = difflib.ndiff(lines1, lines2) 

print "\n ----- SHOW DIFF ----- \n" 
for i, line in enumerate(diffSequence):
    print line

diffObj = difflib.Differ() 
deltaSequence = diffObj.compare(lines1, lines2) 
deltaList = list(deltaSequence) 

print "\n ----- SHOW DELTALIST ----- \n" 
for i, line in enumerate(deltaList):
    print line



#let's suppose we store just the diffSequence in the database 
#then we want to take the current file (file2) and recreate the original (file1) from it
#by backward applying the diff 

restoredFile1Lines = difflib.restore(diffSequence,1)  # 1 indicates file1 of 2 used to create the diff 

restoreFileList = list(restoredFile1Lines)

print "\n ----- SHOW REBUILD OF FILE1 ----- \n" 
# this is not showing anything! 
for i, line in enumerate(restoreFileList): 
    print line

Merci!

Mise à jour:

contextDiffSeq = difflib.context_diff(lines1, lines2) 
contextDiffList = list(contextDiffSeq) 

print "\n ----- SHOW CONTEXTDIFF ----- \n" 
for i, line in enumerate(contextDiffList):
    print line
  

----- ----- MONTRER CONTEXTDIFF

     
     
     
     

* ** 5,9

 print "HIJ"

 print "JKL"

 print "Hello World"
     
      
  • print "j =" + j

         

    print "XYZ"

  •   
     

--- ---- 5,9

 print "HIJ"

 print "JKL"

 print "Hello World"

 print "XYZ"
     
      
  • print "La fin"
  •   

Une autre mise à jour:

Dans l'ancien temps de Panvalet un bibliothécaire, des outils de gestion de source pour l'ordinateur central, vous pouvez créer un changeset comme ceci:

++ADD 9
   print "j=" + j 

Ce qui signifie simplement ajouter une ligne (ou lignes), après la ligne 9. Ensuite, il y a des mots comme mot ++ ou ++ REMPLACER UPDATE. http://www4.hawaii.gov/dags/icsd/ppmo /Stds_Web_Pages/pdf/it110401.pdf

Était-ce utile?

La solution

Diffs doit contenir suffisamment d'informations pour permettre de patcher une version dans une autre, donc oui, pour votre expérience d'un changement d'une seule ligne à un très petit document, le stockage des documents entiers pourraient être moins chers.

Fonctions de bibliothèque retour itérateurs pour le rendre plus facile sur les clients qui sont serrés sur la mémoire ou seulement besoin de regarder une partie de la séquence résultante. Il est ok en Python parce que chaque iterator peut être converti en une liste avec une très courte expression list(an_iterator).

La plupart differentiation est fait sur les lignes de texte, mais il est possible de descendre à l'omble chevalier par char, et le fait difflib. Jetez un oeil à la classe Differ d'objet dans difflib.

Les exemples tous sur l'utilisation du lieu de sortie convivial humain, mais les diffs sont gérés en interne d'une manière, conviviale ordinateur beaucoup plus compact. En outre, diffs contiennent généralement des informations redondantes (comme le texte d'une ligne à supprimer) pour apporter des modifications rapiéçage et la fusion en toute sécurité. La redondance peut être supprimé par votre propre code, si vous vous sentez à l'aise avec cela.

Je viens de lire que opts difflib pour le moins surprenant en faveur de l'optimalité, ce qui est quelque chose que je ne discuterai pas contre. Il y a rel="nofollow"> algorithmes qui sont rapides à produire un ensemble minimum de changements.

Une fois, je codé un moteur générique diffing avec l'un des algorithmes optimaux dans environ 1250 lignes de Java ( JRCS ). Il travaille pour une séquence d'éléments qui peuvent être comparés pour l'égalité. Si vous voulez construire votre propre solution, je pense qu'une traduction / reimplementation de JRCS ne devrait pas prendre plus de 300 lignes de Python.

Traitement de la sortie produite par difflib pour le rendre plus compact est également une option. Ceci est un exemple d'un petit fichier avec trois changements (un ajout, un changement, et une suppression):

---  
+++  
@@ -7,0 +7,1 @@
+aaaaa
@@ -9,1 +10,1 @@
-c= 0
+c= 1
@@ -15,1 +16,0 @@
-    m = re.match(code_re, text)

Qu'est-ce que le patch dit peut être facilement condensé à:

+7,1 
aaaaa
-9,1 
+10,1
c= 1
-15,1

Pour votre propre exemple, la sortie condensée serait:

-8,1
+9,1
print "The end"

Pour la sécurité, laissant un marqueur de premier plan ( « > ») pour les lignes qui doivent être insérées pourrait être une bonne idée.

-8,1
+9,1
>print "The end"

Est-ce plus proche de ce dont vous avez besoin?

Ceci est une fonction simple compacter. Vous devez écrire votre propre code pour appliquer le correctif dans ce format, mais il devrait être simple.

def compact_a_unidiff(s):
    s = [l for l in s if l[0] in ('+','@')]
    result = []
    for l in s:
        if l.startswith('++'):
            continue
        elif l.startswith('+'):
            result.append('>'+ l[1:])
        else:
            del_cmd, add_cmd = l[3:-3].split()
            del_pair, add_pair = (c.split(',') for c in (del_cmd,add_cmd))
            if del_pair[1]  != '0':
                result.append(del_cmd)
            if add_pair[1] != '0':
                result.append(add_cmd)
    return result

Autres conseils

  

Je suis aussi essayer encore de comprendre   pourquoi de nombreuses fonctions de difflib renvoient un   générateur au lieu d'une liste, ce qui est   l'avantage il?

Eh bien, pensez à ce sujet pour une seconde - si vous comparez les fichiers, ces fichiers peuvent en théorie (et sera en pratique) être assez grand - retour le delta comme une liste, pour exampe, des moyens de lecture des données complètes en mémoire , ce qui est pas une chose intelligente à faire.

En ce qui concerne uniquement le retour de la différence, eh bien, il y a un autre avantage à utiliser un générateur -. Juste itérateur sur le delta et garder ce que les lignes qui vous intéresse

Si vous lisez la documentation difflib Differ - deltas de style, vous verrez un paragraphe qui se lit comme suit:

Each line of a Differ delta begins with a two-letter code:
Code    Meaning
'- '    line unique to sequence 1
'+ '    line unique to sequence 2
'  '    line common to both sequences
'? '    line not present in either input sequence

Donc, si vous ne souhaitez que des différences, vous pouvez facilement filtrer les en utilisant str.startsWith

Vous pouvez également utiliser difflib.context_diff pour obtenir un delta compact qui ne montre que les changements.

Vous voulez utiliser la diff unifié ou d'un contexte si vous voulez juste les changements. Vous voyez des fichiers plus gros car il inclut les lignes qu'ils ont en commun.

L'avantage de retourner un générateur est que la chose entière n'a pas besoin d'être tenue en mémoire à la fois. Cela peut être utile pour comparer des fichiers très volumineux.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top