2010-02-21 3 views
24

Есть ли способ «из коробки» в python, чтобы создать список различий между двумя текстами, а затем применить этот diff к одному файлу для получения другого позже?Создание и применение различий в python

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

ответ

25

Был ли у вас взгляд на diff-match-patch из Google? Очевидно, Google Docs использует этот набор алгоритмов. Он включает в себя не только модуль diff, но и модуль патча, поэтому вы можете создавать новейший файл из более старых файлов и разностей.

Включена версия python.

http://code.google.com/p/google-diff-match-patch/

+1

Именно то, что я искал! Я пытался использовать Google для разных комбинаций «python», «diff», «patch», «revision», но пока не нашел этого. – noio

+0

google-diff-match-patch действительно хранит весь файл. Он сохраняет все в кортежах: (0, «stuff») означает, что «материал» присутствует в обеих строках. Система достаточно проста, что она хранит буквально каждый символ, чтобы он мог перебирать их и модифицировать текст по мере необходимости. – Paragon

+0

Как я могу использовать этот API с Python>? Было бы здорово, если бы это можно было проиллюстрировать с помощью примера – qre0ct

1

Должно ли это быть решение python?
Мое первое соображение относительно решения заключалось бы в использовании либо системы управления версиями (Subversion, Git и т. Д.), Либо утилит diff/patch, которые являются стандартными для системы unix или являются частью cygwin для системы на базе Windows ,

+1

Это должно быть чистое решение python, потому что я хотел бы развернуть его в AppEngine. 'diff' /' patch' был бы идеальным, но затем в python. – noio

+0

Обратите внимание, что подобные вычисления, как правило, медленные, поэтому, вероятно, что-то более низкое будет масштабироваться лучше! – Pithikos

2

AFAIK алгоритмы большинства различий используют простое совпадение Longest Common Subsequence, чтобы найти общую часть между двумя текстами и тем, что осталось, считается разницей. Не слишком сложно кодировать собственный алгоритм динамического программирования, чтобы выполнить это в python, страница с википедии выше также предоставляет алгоритм.

10

ли difflib.unified_diff хочет вы хотите? Существует пример here.

+0

Проголосовал за свой ответ , Встроенный difflib кажется мощным, но несколько запутанным, просто вопрос преодоления кривой обучения. См. Мой аналогичный пост здесь: http://stackoverflow.com/questions/4743359/python-difflib-deltas-and-compare-ndiff/4743621#4743621 – NealWalters

+4

В библиотеке нет способа применить вывод 'difflib.unified_diff'. Он имеет 'diff', но не' patch'. Таким образом, если вы пытаетесь оставаться внутри python, 'difflib.unified_diff' бесполезен. –

0

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

diff = difflib.unified_diff(old_file, new_file, lineterm='') 
    lines = list(diff)[2:] 
    # linesT = list(diff)[0:3] 
    print (lines[0]) 
    added = [lineA for lineA in lines if lineA[0] == '+'] 


    with open("output.txt", "w") as fh1: 
    for line in added: 
     fh1.write(line) 
    print '+',added 
    removed = [lineB for lineB in lines if lineB[0] == '-'] 
    with open("output.txt", "a") as fh1: 
    for line in removed: 
     fh1.write(line) 
    print '-',removed 

Используйте это в своем коде, чтобы сохранить только разностный выход!

1

Я реализовал чистую функцию python для применения патчей diff для восстановления любой из входных строк, я надеюсь, что кто-то сочтет это полезным. Он использует разбор Unified diff format.

import re 

_hdr_pat = re.compile("^@@ -(\d+),?(\d+)? \+(\d+),?(\d+)? @@$") 

def apply_patch(s,patch,revert=False): 
    """ 
    Apply unified diff patch to string s to recover newer string. 
    If revert is True, treat s as the newer string, recover older string. 
    """ 
    s = s.splitlines(True) 
    p = patch.splitlines(True) 
    t = '' 
    i = sl = 0 
    (midx,sign) = (1,'+') if not revert else (3,'-') 
    while i < len(p) and p[i].startswith(("---","+++")): i += 1 # skip header lines 
    while i < len(p): 
    m = _hdr_pat.match(p[i]) 
    if not m: raise Exception("Cannot process diff") 
    i += 1 
    l = int(m.group(midx))-1 + (m.group(midx+1) == '0') 
    t += ''.join(s[sl:l]) 
    sl = l 
    while i < len(p) and p[i][0] != '@': 
     if i+1 < len(p) and p[i+1][0] == '\\': line = p[i][:-1]; i += 2 
     else: line = p[i]; i += 1 
     if len(line) > 0: 
     if line[0] == sign or line[0] == ' ': t += line[1:] 
     sl += (line[0] != sign) 
    t += ''.join(s[sl:]) 
    return t 

Если есть строки заголовка ("--- ...\n","+++ ...\n") он пропускает через них.Если мы имеем единый дифф строку diffstr, представляющие различия между oldstr и newstr:

# recreate `newstr` from `oldstr`+patch 
newstr = apply_patch(oldstr, diffstr) 
# recreate `oldstr` from `newstr`+patch 
oldstr = apply_patch(newstr, diffstr, True) 

В Python, вы можете создать унифицированный формат двух строк с помощью difflib (часть стандартной библиотеки):

import difflib 
_no_eol = "\ No newline at end of file" 

def make_patch(a,b): 
    """ 
    Get unified string diff between two strings. Trims top two lines. 
    Returns empty string if strings are identical. 
    """ 
    diffs = difflib.unified_diff(a.splitlines(True),b.splitlines(True),n=0) 
    try: _,_ = next(diffs),next(diffs) 
    except StopIteration: pass 
    return ''.join([d if d[-1] == '\n' else d+'\n'+_no_eol+'\n' for d in diffs]) 

на UNIX: diff -U0 a.txt b.txt

код на GitHub здесь наряду с тестами с использованием ASCII и случайных символов Юникода: https://gist.github.com/noporpoise/16e731849eb1231e86d78f9dfeca3abc

 Смежные вопросы

  • Нет связанных вопросов^_^