Pregunta

¿Hay una manera 'fuera de la caja' en Python para generar una lista de diferencias entre los dos textos, y luego aplicar este diff a un archivo para obtener la otra, más adelante?

Quiero mantener el historial de revisión de un texto, pero no desea guardar el texto entero para cada revisión si sólo hay una sola línea editado. Miré a difflib , pero no pude ver cómo generar una lista de sólo el líneas editadas que todavía se pueden utilizar para modificar un texto a obtener los otros.

¿Fue útil?

Solución

¿Tuvo un vistazo a diff-partido-corrección del google? Aparentemente Google Docs utiliza este conjunto de algoritms. Incluye no sólo un módulo de diferencias, pero también un módulo de parche, por lo que puede generar el archivo más reciente de los archivos más antiguos y diferenciaciones.

Se incluye la versión pitón A.

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

Otros consejos

¿El difflib.unified_diff no quiere que usted quiere? Hay un ejemplo aquí .

Que yo sepa la mayoría de los algoritmos usan un simple diff común más larga subsecuencia partido, para encontrar la parte común entre dos textos y lo que queda se considera la diferencia. No debería ser demasiado difícil de codificar su propio algoritmo de programación dinámica para lograr que en Python, la página de Wikipedia anterior proporciona el algoritmo también.

He implementado una función de Python puro para aplicar los parches diff para recuperar cualquiera de las cadenas de entrada, espero que encuentre a alguien que útiles. Utiliza analiza el Unificado formato diff .

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 cabecera ("--- ...\n","+++ ...\n") se salta por encima de ellos. Si tenemos una cadena de diffstr diff unificado que representa el diff 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 se puede generar un diff unificado de dos cadenas utilizando 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 es en GitHub aquí, junto con las pruebas que utilizan ASCII y caracteres Unicode al azar: https: // GIST. github.com/noporpoise/16e731849eb1231e86d78f9dfeca3abc

¿Tiene que ser una solución pitón?
Mis primeros pensamientos como a una solución sería utilizar ya sea una versión del sistema de control (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.

Probablemente se puede utilizar unified_diff para generar la lista de diferencia en un archivo . Solo los textos modificados en su archivo se puede escribir en un archivo de texto nuevo donde se puede utilizar para su referencia futura. Este es el código que le ayuda a escribir sólo la diferencia a su nuevo archivo. Espero que esto es lo que está 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 

Utilice esta en el código para guardar sólo la salida de diferencia!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top