Domanda

C'è un modo 'out-of-the-box' in python per generare un elenco di differenze tra i due testi, e quindi l'applicazione di questo diff in un unico file per ottenere l'altra, più tardi?

Voglio mantenere la cronologia di revisione di un testo, ma io non voglio salvare l'intero testo per ogni revisione se v'è solo una singola linea modificato. Ho guardato difflib , ma non ho potuto vedere come generare un elenco di solo il linee modificati che possono ancora essere utilizzati per modificare un testo per ottenere l'altro.

È stato utile?

Soluzione

Hai uno sguardo al diff match-patch da Google? A quanto pare Google Documenti utilizza questo insieme di algoritmi. Esso comprende non solo un modulo diff, ma anche un modulo di patch, in modo da poter generare il file più recente dai file più grandi e diff.

Una versione di Python è incluso.

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

Altri suggerimenti

La difflib.unified_diff voglio che si desidera? C'è un esempio qui .

AFAIK maggior parte degli algoritmi diff usano un semplice corrispondenza più lunga Comune Subsequence , per trovare la parte comune tra i due testi e tutto ciò che è sinistra è considerata la differenza. Non dovrebbe essere troppo difficile da codificare il proprio algoritmo di programmazione dinamica per realizzare questo in python, la pagina di wikipedia sopra fornisce l'algoritmo di troppo.

Ho implementato una funzione di puro Python per applicare le patch diff di recuperare uno dei due stringhe di input, spero che qualcuno lo trova utile. Esso utilizza analizza i href="https://en.wikipedia.org/wiki/Diff_utility#Unified_format" unificata 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

Se ci sono linee di intestazione ("--- ...\n","+++ ...\n") salta su di loro. Se abbiamo un diffstr stringa di diff unificato che rappresenta la diff tra oldstr e newstr:

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

In Python è possibile generare un diff unificato di due stringhe con difflib (parte della libreria standard):

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

Su UNIX: diff -U0 a.txt b.txt

Codice è su GitHub qui con test utilizzando ASCII e caratteri Unicode casuali: https: // Gist. github.com/noporpoise/16e731849eb1231e86d78f9dfeca3abc

Essa non deve essere una soluzione pitone?
I miei primi pensieri come ad una soluzione potrebbe essere quella di utilizzare un sistema di controllo di versione (Subversion, Git, ecc) o le utilità diff / patch che sono standard con un sistema Unix, o fanno parte di cygwin per un Windows sistema basato.

Probabilmente è possibile utilizzare unified_diff per generare l'elenco di differenza in un file . i testi modificati nel file possono essere scritti solo in un nuovo file di testo in cui è possibile utilizzare per il vostro riferimento futuro. Questo è il codice che vi aiuta a scrivere solo la differenza per il nuovo file. Spero che questo è ciò che stai chiedendo!

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 

Utilizza questo nel codice di salvare solo l'uscita differenza!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top