Вопрос

Я хотел сделать что -то вроде того, что я считаю, что делают системы управления изменениями, они сравнивают два файла и сохраняют небольшую дифференциацию каждый раз, когда файл меняется. Я читал эту страницу: http://docs.python.org/library/difflib.html И это, очевидно, не погружается в мою голову.

Я пытался воссоздать это в несколько простой программе, показанной ниже, но мне, кажется, не хватает того, что дельта содержит, по крайней мере, столько же, сколько исходный файл и многое другое.

Разве невозможно получить только чистые изменения? Причина, по которой я прошу, надеюсь, очевидна - сохранить пространство диска.
Я мог бы просто сохранить всю часть кода каждый раз, но было бы лучше сохранить текущий код один раз, а затем небольшие различия в изменениях.

Я также все еще пытаюсь выяснить, почему многие функции Difflib возвращают генератор вместо списка, какое преимущество там?

Будет ли Difflib работать для меня - или мне нужно найти более профессиональный пакет с большим количеством функций?

# 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

Спасибо!

ОБНОВИТЬ:

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"
  • Печать "j =" + j

    Печать "xyz"

--- 5,9 ----

 print "HIJ"

 print "JKL"

 print "Hello World"

 print "XYZ"
  • Печать "Конец"

Еще одно обновление:

В старые времена Панвалета библиотекарь, инструменты управления источниками для мэйнфрейма, вы можете создать такого набора изменений:

++ADD 9
   print "j=" + j 

Что означает просто добавить строку (или строки) после строки 9. Тогда есть слова слова, такие как ++, заменить или ++ обновление.http://www4.hawaii.gov/dags/icsd/ppmo/stds_web_pages/pdf/it110401.pdf

Это было полезно?

Решение

Diff должны содержать достаточное количество информации, чтобы сделать возможным разместить версию в другую, так что да, для вашего эксперимента с однострочным изменением в очень маленький документ, хранение всего документов может быть дешевле.

Библиотечные функции возвращают итераторы, чтобы упростить клиенты, которые тесно связаны с памятью или должны только взглянуть на часть полученной последовательности. Это нормально в Python, потому что каждый итератор может быть преобразован в список с очень коротким list(an_iterator) выражение.

Большинство различий осуществляется на строках текста, но можно спуститься до чара, и difflib Имеет ли это. Взглянуть на Differ класс объекта в difflib.

Примеры повсюду используют выходные продукты для человека, но различия управляются внутри, гораздо более компактным, удобным для компьютера. Кроме того, различия обычно содержат избыточную информацию (например, текст линии для удаления) для обеспечения безопасности исправления и объединения изменений. Избыточность может быть удалена вашим собственным кодом, если вы чувствуете себя комфортно с этим.

Я только что прочитал это difflib Выбирает наименьшее количество закупок в пользу оптимальности, с чем я не буду спорить. Есть хорошо известно Алгоритмы, которые быстрые при создании минимального набора изменений.

Однажды я закодировал общий дифференциальный двигатель вместе с одним из оптимальных алгоритмов примерно в 1250 линиях Java (JRCS) Он работает для любой последовательности элементов, которые можно сравнить для равенства. Если вы хотите создать свое собственное решение, я думаю, что перевод/повторное развлечение JRC должно занимать не более 300 линий Python.

Обработка вывода, произведенных difflib Сделать его более компактным также вариант. Это пример из небольших файлов с тремя изменениями (добавление, изменение и удаление):

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

То, что говорит, может быть легко сжат:

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

Для вашего собственного примера конденсированный выход был:

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

Для безопасности, оставление в ведущем маркере ('>') для линий, которые должны быть вставлены, может быть хорошей идеей.

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

Это ближе к тому, что вам нужно?

Это простая функция для выполнения уплотнения. Вам придется написать свой собственный код, чтобы применить патч в этом формате, но он должен быть простым.

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

Другие советы

Я также все еще пытаюсь выяснить, почему многие функции Difflib возвращают генератор вместо списка, какое преимущество там?

Что ж, подумайте об этом на секунду - если вы сравниваете файлы, эти файлы могут в теории (и будут на практике) быть довольно большими - возвращать дельту в качестве списка, для exampe означает чтение полных данных в память, которая является Не разумно сделать.

Что касается только возврата разницы, то есть еще одно преимущество в использовании генератора - просто итерация над дельтой и сохраните любые линии, которые вас интересуют.

Если вы прочитаете Difflib документация Для отличия - стиль Deltas, вы увидите абзац, в котором говорится:

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

Итак, если вам нужны только различия, вы можете легко отфильтровать их, используя Str.StartSwith

Вы также можете использовать difflib.context_diff Чтобы получить компактную дельту, которая показывает только изменения.

Вы хотите использовать Unified или Context Diff, если вам просто хотите изменения. Вы видите более крупные файлы, потому что они включают в себя линии, которые у них есть общие.

Преимущество возврата генератора заключается в том, что все это не нужно удерживаться в памяти одновременно. Это может быть полезно для разнообразия очень больших файлов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top