Frage

Ich war auf der Suche, wie etwas zu tun, was ich glaube, Change Control Systeme tun, sie zwei Dateien vergleichen und eine kleine diff die Datei ändert sich jedes Mal speichern. Ich habe diese Seite gelesen: http://docs.python.org/library/difflib.html und es versinkt nicht in meinem Kopf offenbar.

Ich habe versucht, dies in einem etwas einfachen Programm neu zu erstellen unten gezeigt, aber das, was ich scheine ist zu fehlen, dass die Deltas mindestens so viel enthalten wie die Originaldatei und vieles mehr.

Ist es nicht möglich, nur die reinen Veränderungen zu bekommen? Der Grund, warum ich frage ist hoffentlich klar - um Speicherplatz zu sparen
. Ich konnte es einfach speichert das gesamte Stück Code jedes Mal, aber es wäre besser, wenn aktuellen Code zu speichern, dann kleine diffs der Änderungen.

Ich versuche auch immer noch herauszufinden, warum viele difflib Funktionen einen Generator anstelle einer Liste zurück, was ist der Vorteil dort?

Will difflib Arbeit für mich - oder ich brauche ein professionelles Paket mit mehr Funktionen zu finden?

# 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

Danke!

UPDATE:

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

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

----- SHOW CONTEXTDIFF -----




* 5,9 **

 print "HIJ"

 print "JKL"

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

    print "XYZ"

--- ---- 5,9

 print "HIJ"

 print "JKL"

 print "Hello World"

 print "XYZ"
  • Drucken "Das Ende"

Ein weiteres Update:

In den alten Tagen von Panvalet eine Bibliothekarin, Quelle-Management-Tools für den Mainframe, könnten Sie eine changeset wie diese erstellen:

++ADD 9
   print "j=" + j 

Was einfach bedeutet eine Linie hinzufügen (oder Zeilen) nach Linie 9. Dann gibt Wort Wörter wie ++ REPLACE oder ++ UPDATE. http://www4.hawaii.gov/dags/icsd/ppmo /Stds_Web_Pages/pdf/it110401.pdf

War es hilfreich?

Lösung

Diffs muss genügend Informationen enthalten, um es möglich zu machen, eine Version in eine anderen Patch, also ja, für den Test eines einzeiligen Wechsels zu einem sehr kleinen Dokument, die ganzen Dokumente zu speichern könnten billiger sein.

In der Bibliothek Funktionen geben Iteratoren es einfacher, auf Kunden zu machen, das fest auf Speicher oder nur an einem Teil der resultierenden Sequenz zu suchen. Es ist in Ordnung, in Python, weil jeder Iterator kann mit einem sehr kurzen list(an_iterator) Ausdruck in eine Liste umgewandelt werden.

Die meisten differenzier auf Textzeilen getan, aber es ist möglich, die char-by-char zu gehen, und difflib tut es. Werfen Sie einen Blick auf die Differ Objektklasse in difflib.

Die Beispiele alle über die Platz Verwendung menschenfreundliche Ausgabe, aber die diffs werden intern in eine viel kompakten, computerfreundliche Art und Weise verwaltet werden. Außerdem enthalten diffs in der Regel redundante Informationen (wie der Text einer Zeile zu löschen), um das Patchen und Zusammenführen von Änderungen sicher. Die Redundanz kann durch Ihren eigenen Code entfernt werden, wenn Sie mit, dass sich wohl fühlen.

Ich habe gerade gelesen, dass difflib entscheidet sich für die am wenigsten Überraschung für Optimalität, die etwas ist, ich werde nicht gegen streiten. Es gibt gut Algorithmen bekannt, die schnell auf ein Minimum an Veränderungen zu erzeugen.

Ich habe einmal einen allgemeinen diffing Motor codierte zusammen mit einem der optimalen Algorithmen in etwa 1250 Zeilen von Java ( JRCS ). Es funktioniert für jede Folge von Elementen, die für die Gleichheit verglichen werden. Wenn Sie Ihre eigene Lösung aufbauen wollen, glaube ich, dass eine Übersetzung / Reimplementation JRCS sollte nicht mehr als 300 Zeilen Python nehmen.

die Ausgabe von difflib erzeugt wird bearbeitet, um es kompakt zu machen ist auch eine Option. Dies ist ein Beispiel von einem kleinen Datei mit drei Änderungen (eine Addition, eine Änderung und eine Deletion):

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

Was der Patch sagt leicht zu kondensieren:

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

Für Ihr eigenes Beispiel der kondensierte Ausgabe wäre:

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

Zur Sicherheit in einer führenden Markierung verlassen ( ‚>‘) für Linien, die möglicherweise eine gute Idee eingesetzt werden muss.

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

Ist das näher an, was Sie brauchen?

Dies ist eine einfache Funktion des Verdichtungs zu tun. Sie werden Ihren eigenen Code schreiben müssen den Patch in diesem Format gelten, aber es sollte einfach sein.

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

Andere Tipps

Ich versuche auch immer noch herauszufinden, warum viele difflib Funktionen geben ein Generator statt einer Liste, was ist der Vorteil, da?

Nun, denken sie für eine zweite - wenn Sie Dateien zu vergleichen, können diese Dateien in der Theorie (und in der Praxis sein wird) ziemlich groß sein - Rückkehr der Delta als eine Liste, für exampe, Mittel, um die vollständigen Daten in den Speicher einzulesen , das nicht ein intelligentes, was zu tun ist.

Was nur die Differenz zurückkehrt, na ja, es ist ein weiterer Vorteil, einen Generator in Verwendung -. Nur Iterierte über das Delta und halten, was Linien, die Sie daran interessiert sind,

Wenn Sie die difflib Dokumentation lesen für Differ - Stil Deltas, Sie werden einen Absatz sehen, der lautet:

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

Wenn Sie also nur Unterschiede möchten, können Sie einfach diejenigen herauszufiltern, indem Sie str.startswith

Sie können auch difflib.context_diff verwenden, um eine kompakte Delta, die zeigt, zu erhalten, nur die Änderungen.

Sie möchten die einheitliche oder Kontext diff verwenden, wenn Sie nur die Änderungen wollen. Sie sehen, größere Dateien, weil sie die Linien, die sie gemeinsam haben, enthält.

Der Vorteil einen Generator der Rückkehr ist, dass die ganze Sache nicht auf einmal im Speicher gehalten werden muss. Dies kann für die Differenzen zwischen sehr großen Dateien nützlich sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top