34

Pythonには、2つのテキスト間の相違点のリストを生成し、この差分を一方のファイルに適用してもう一方のファイルを後で取得する「すぐに使える」方法はありますか?

テキストの改訂履歴を保持したいのですが、編集した行が1つしかない場合は、改訂ごとにテキスト全体を保存したくありません。difflibを見ましたが、編集された行だけのリストを生成する方法がわかりませんでした。このリストを使用して、一方のテキストを変更してもう一方のテキストを取得することができます。

4

6 に答える 6

28

Google の diff-match-patch を見ましたか? どうやらGoogle Docsはこの一連のアルゴリズムを使用しています。差分モジュールだけでなく、パッチモジュールも含まれているので、古いファイルや差分から最新のファイルを生成できます。

Python バージョンが含まれています。

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

于 2010-02-21T22:39:28.340 に答える
12

difflib.unified_diff は必要ですか? ここに例があります。

于 2010-02-21T22:39:35.877 に答える
5

入力文字列のいずれかを回復するために差分パッチを適用する純粋な python 関数を実装しました。これは、 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の間の差分を表す統一された差分文字列がある場合:oldstrnewstr

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

Python では、 difflib (標準ライブラリの一部)を使用して、2 つの文字列の統合 diff を生成できます。

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

コードは、ASCII およびランダムな Unicode 文字を使用したテストとともに GitHub にあります。

于 2016-12-05T04:55:09.587 に答える
1

私の知る限り、ほとんどの差分アルゴリズムは単純な最長共通サブシーケンス一致を使用して、2 つのテキスト間の共通部分を見つけ、残っているものはすべて違いと見なされます。Pythonでそれを達成するために独自の動的プログラミングアルゴリズムをコーディングすることはそれほど難しくないはずです。上記のウィキペディアのページでもアルゴリズムが提供されています。

于 2010-02-21T21:34:57.490 に答える
0

Pythonソリューションである必要がありますか?
解決策についての私の最初の考えは、バージョン管理システム(Subversion、Gitなど)またはUNIXシステムに標準であるかWindowsベースのシステムの一部であるdiff/patchユーティリティのいずれかを使用することです。cygwin

于 2010-02-21T21:18:06.533 に答える
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 

コードでこれを使用して、差分出力のみを保存してください。

于 2016-03-09T11:13:15.457 に答える