with tutorial framework espaƱol djangoproject desde con cero applications python diff revision difflib

python - framework - tutorial django



Generando y aplicando diffs en python. (6)

¿Difflib.unified_diff quiere que quieras? Hay un ejemplo here .

¿Existe una forma ''fuera de la caja'' en Python para generar una lista de diferencias entre dos textos y luego aplicar esta diferencia a un archivo para obtener el otro, más adelante?

Quiero mantener el historial de revisión de un texto, pero no quiero guardar todo el texto para cada revisión si solo hay una línea editada. Miré difflib , pero no pude ver cómo generar una lista de solo las líneas editadas que todavía se pueden usar para modificar un texto para obtener el otro.


¿Has echado un vistazo a diff-match-patch de google? Al parecer, Google Docs utiliza este conjunto de algoritmos. Incluye no solo un módulo de diferencias, sino también un módulo de parches, para que pueda generar el archivo más nuevo a partir de archivos y diferencias más antiguos.

Se incluye una versión de python.

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


¿Tiene que ser una solución de python?
Mi primer pensamiento acerca de una solución sería utilizar un Sistema de control de versiones (Subversion, Git, etc.) o las utilidades diff / patch que son estándar con un sistema Unix, o son parte de cygwin para un sistema basado en Windows.


He implementado una función python pura para aplicar parches de diferencia para recuperar cualquiera de las cadenas de entrada, espero que alguien lo encuentre útil. Utiliza los análisis del formato unificado .

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

Si hay líneas de encabezado ("--- .../n","+++ .../n") omite. Si tenemos una cadena de diferencias unificada que representa la diferencia entre oldstr y newstr :

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

En Python puedes generar un diff unificado de dos cadenas usando difflib (parte de la biblioteca estándar):

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])

En unix: diff -U0 a.txt b.txt

El código está en GitHub aquí junto con las pruebas que usan ASCII y caracteres aleatorios Unicode: https://gist.github.com/noporpoise/16e731849eb1231e86d78f9dfeca3abc


Los algoritmos AFAIK most difieren una coincidencia más larga común de subsecuencias , para encontrar la parte común entre dos textos y lo que quede se considera la diferencia. No debería ser demasiado difícil codificar su propio algoritmo de programación dinámica para lograr eso en python, la página de wikipedia de arriba también proporciona el algoritmo.


Probablemente puede usar unified_diff para generar la lista de diferencias en un archivo. Solo los textos modificados en su archivo pueden escribirse en un nuevo archivo de texto donde puede usarlo para futuras referencias. Este es el código que le ayuda a escribir solo la diferencia en su nuevo archivo. Espero que esto sea lo que estas pidiendo!

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

¡Use esto en su código para guardar solo la diferencia de salida!