سؤال

هل هناك طريقة "خارج الصندوق" في بيثون لإنشاء قائمة من الاختلافات بين نصين ، ثم تطبيق هذا الفرق على ملف واحد للحصول على الآخر ، لاحقًا؟

أرغب في الاحتفاظ بسجل المراجعة للنص ، لكنني لا أريد حفظ النص بأكمله لكل مراجعة إذا كان هناك مجرد سطر واحد تم تحريره. نظرت إلى Difflib, ، لكنني لم أستطع رؤية كيفية إنشاء قائمة بالخطوط المعدلة التي لا يزال من الممكن استخدامها لتعديل نص واحد للحصول على الآخر.

هل كانت مفيدة؟

المحلول

هل ألقيت نظرة على Diff-Match-Patch من Google؟ تستخدم مستندات Google بشكل واضح هذه المجموعة من الخوارزف. لا يتضمن فقط وحدة Diff ، ولكن أيضًا وحدة تصحيح ، بحيث يمكنك إنشاء أحدث ملف من الملفات القديمة والفرق.

يتم تضمين نسخة بيثون.

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

نصائح أخرى

هل تريد difflib.unified_diff أنك تريد؟ هناك مثال هنا.

AFAIK معظم خوارزميات الفرق تستخدم بسيطة أطول بعد شائع تطابق ، للعثور على الجزء المشترك بين نصين وأي شيء متبقي يعتبر الفرق. لا ينبغي أن يكون من الصعب للغاية ترميز خوارزمية البرمجة الديناميكية الخاصة بك لإنجاز ذلك في بيثون ، توفر صفحة ويكيبيديا أعلاه الخوارزمية أيضًا.

لقد قمت بتطبيق وظيفة Python النقية لتطبيق تصحيحات Diff لاستعادة أي من سلاسل الإدخال ، وآمل أن يجدها شخص ما مفيدًا. ويستخدم التحليلات تنسيق 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

إذا كانت هناك خطوط رأس ("--- ...\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])

على يونيكس: diff -U0 a.txt b.txt

الكود موجود على github هنا مع اختبارات باستخدام أحرف ASCII و Random Unicode: https://gist.github.com/noporpoise/16e731849eb1231e86d78f9dfeca3abc

هل يجب أن يكون حل بيثون؟
تتمثل أفكاري الأولى فيما يتعلق بحل ما في استخدام نظام التحكم في الإصدار (التخريب ، git ، إلخ) أو diff / patch الأدوات المساعدة المعيارية مع نظام UNIX ، أو جزء من cygwin لنظام Windows.

ربما يمكنك استخدام 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 

استخدم هذا في الكود الخاص بك لحفظ فقط إخراج الفرق!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top