Fark Algoritması? [kapalı]


164

Çalışan ve verimli bir fark algoritması açıklaması için deli gibi bakıyordum.

Aldığım en yakın RFC 3284'e (birkaç Eric Sink blog yazısından), fark sonuçlarının saklandığı veri formatını mükemmel bir şekilde anlaşılabilir terimlerle açıklayan bu bağlantı . Ancak, bir programın bir fark yaratırken bu sonuçlara nasıl ulaşacağından bahsedilmez.

Bunu kişisel meraktan araştırmaya çalışıyorum, çünkü bir dif algoritmasını uygularken, bazen diffs'ye bakıp merak ettiğinizde oldukça net olan "dengesizlikler olması gerektiğine eminim" fark programı bunu neden bir değişiklik olarak seçti? bunun yerine?"...

VCDIFF çıktısını verecek etkili bir algoritmanın açıklamasını nerede bulabilirim?
Bu arada, SourceGear'ın DiffMerge tarafından kullanılan gerçek algoritmanın bir tanımını bulursanız, bu daha da iyi olurdu.

NOT: en uzun ortak alt sekans, VCDIFF tarafından kullanılan algoritma gibi görünmüyor, kullandıkları veri formatı göz önüne alındığında daha akıllı bir şey yapıyor gibi görünüyor.


Vikipedi'de hiçbir şey yok mu? Belki de Python gibi bir yükseklik seviyesinde bir anakartta, C uygulamasından daha kolay anlaşılabilecek başka bir uygulama bulmayı deneyebilirsiniz. Python kolayca okunabilir olmasıyla ünlüdür? Python'da bir farksızlık var. İşte kaynağın URL'si. Kaynak fark algoritmaları hakkında tonlarca yorum içeriyor. svn.python.org/view/python/trunk/Lib/…
bsergean

4
RFC'lerin algoritmaları tanımlaması amaçlanmamıştır. Arayüzleri (/ protokolleri) tanımlamak içindir.

2
Aslında, diff algoritmasının çekirdeği, en uzun ortak alt dizi problemi Wikipedia'da bulunabilir. Bu sayfa, özel bir fark yazmam
Corwin Joy

3
Belki de bu yardımcı olacaktır: paulbutler.org/archives/a-simple-diff-algorithm-in-php Kesinlikle harika ve çok küçük (sadece 29 satır ; 2 işlevi var). Stack Overflow'un düzenleme revizyon karşılaştırması şeyine benzer.
Nathan

VCDIFF insan tarafından okunabilen farklar için değildir. Çoğu düz metin fark algoritması tarafından yayılan daha insan tarafından okunabilir silme ve ekleme talimatlarının aksine ekleme, kopyalama ve çalıştırma talimatları kullanır. VCDIFF için burada açıklanan xdelta algoritması gibi bir şeye ihtiyacınız var xmailserver.org/xdfs.pdf
asgerhallas

Yanıtlar:


175

Bir O (ND) Fark Algoritması ve Çeşitleri harika bir kağıttır ve oradan başlamak isteyebilirsiniz. Sahte kod ve farkın yapılmasında yer alan grafik geçişlerinin güzel bir görselleştirmesini içerir.

Makalenin 4. Bölümü algoritmayı çok etkili kılan bazı iyileştirmeler sunmaktadır.

Bunu başarıyla uygulamak, araç kutunuzda çok kullanışlı bir araç bırakacaktır (ve muhtemelen bazı mükemmel deneyimler).

İhtiyacınız olan çıktı formatını oluşturmak bazen zor olabilir, ancak algoritma iç bileşenlerini biliyorsanız, ihtiyacınız olan her şeyi çıktılayabilmeniz gerekir. Çıktıyı etkilemek ve belirli ödünleşmeler yapmak için buluşsal yöntemler de sunabilirsiniz.

Burada, yukarıda belirtilen algoritmadaki teknikleri kullanarak, biraz dokümantasyon, tam kaynak kodu ve bir fark algoritması örnekleri içeren bir sayfa bulunmaktadır .

Kaynak kodu yakından temel algoritma takip etmeye görünür ve kolay okunur.

Ayrıca, girdiyi hazırlarken yararlı bulabileceğiniz biraz da var. Karakter veya jeton (kelime) ile farklılık gösterirken çıktıda büyük bir fark vardır.

İyi şanslar!


1
Bağlantının kötüye gitmesi durumunda, bu Myers 1986; bakınız örneğin citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - ayrıca diffHunt ve McIlroy'un Unix belgesine bir bağlantı içerir .
üçlü

34

Ben gerçek bakarak başlayacak kaynak kodu GNU yapar diff için, mevcut .

Bu kaynak kodun gerçekte nasıl çalıştığını anlamak için, paketteki dokümanlar ilham veren makalelere referansta bulunur:

Temel algoritma "Bir O (ND) Fark Algoritması ve Çeşitleri", Eugene W. Myers, 'Algorithmica' Vol. 1 No. 2, 1986, sayfa 251-266; ve "Bir Dosya Karşılaştırma Programı" nda, Webb Miller ve Eugene W. Myers, 'Software - Practice and Experience' Vol. 15 No.11, 1985, sayfa 1025-1040. Algoritma bağımsız olarak "Yaklaşık Dizi Eşleşmesi için Algoritmalar", E. Ukkonen, `Bilgi ve Kontrol 'Vol. 64, 1985, s. 100-118.

Makaleleri okumak ve daha sonra bir uygulamanın kaynak koduna bakmak, nasıl çalıştığını anlamak için fazlasıyla yeterli olmalıdır.


80
Hmmm, kısaca, bazen temel algoritmayı gerçek kaynak kodundan anlamak (özellikle verimli olacak şekilde optimize edilmişse) oldukça karmaşık olabilir. Programın adım adım ne yaptığını anlayabileceğim, ancak tam olarak "neden" veya bununla ilgili üst düzey bir genel bakış değil ... Örnek: Normal ifadelerin nasıl çalıştığını (veya ne olduklarını) asla anlayamazsınız. Perl's Regexes uygulamasına bakmak. Ya da bunu yapabilirseniz, şapkamı deviriyorum, neler olduğunu anlamak için kesinlikle daha açık, daha yüksek bir genel bakışa ihtiyacım var.
Daniel Magliola

3
Perl'in büyük çoğunluğunun nasıl çalıştığını asla anlayamıyorum :-), ancak paket belgelerinde (güncellemeye bakın) sizi açıklayan literatüre yönlendirecek bir bağlantı var (Perl değil, fark algoritmasıdır).
paxdiablo

32
Kodu okuma. Kağıdı oku.
Ira Baxter

31

Bkz. Https://github.com/google/diff-match-patch

"Diff Match ve Patch kütüphaneleri düz metin senkronizasyonu için gerekli işlemleri gerçekleştirmek için sağlam algoritmalar sunuyor. ... Şu anda Java, JavaScript, C ++, C # ve Python'da mevcut"

Ayrıca bkz. Wikipedia.org Diff sayfası ve - " Bram Cohen: Fark sorunu çözüldü "


2
Cohen'in algoritmasının Sabır Farkı olarak da göründüğünü belirtmek istedim. Pazardaki (varsayılan?) Fark algoritması ve git'te isteğe bağlı bir algoritmadır.
Dale Hagglund

13

Buraya diff algoritmasını aramaya geldim ve daha sonra kendi uygulamamı yaptım. Üzgünüm vcdiff hakkında bilmiyorum.

Vikipedi : En uzun ortak dizilişten, farklı çıktı elde etmek için yalnızca küçük bir adım vardır: bir öğe dizide bulunmuyorsa ancak orijinalinde mevcutsa silinmiş olmalıdır. (Aşağıdaki '-' işaretleri.) Eğer ardışıkta yoksa, ancak ikinci sırada mevcutsa, eklenmiş olmalıdır. ('+' İşaretleri.)

LCS algoritmasının güzel animasyonu burada .

Burada hızlı bir LCS ruby ​​uygulamasına bağlantı .

Yavaş ve basit yakut adaptasyonum aşağıda.

def lcs(xs, ys)
  if xs.count > 0 and ys.count > 0
    xe, *xb = xs
    ye, *yb = ys
    if xe == ye
      return [xe] + lcs(xb, yb)
    end
    a = lcs(xs, yb)
    b = lcs(xb, ys)
    return (a.length > b.length) ? a : b
  end
  return []
end

def find_diffs(original, modified, subsequence)
  result = []
  while subsequence.length > 0
    sfirst, *subsequence = subsequence
    while modified.length > 0
      mfirst, *modified = modified
      break if mfirst == sfirst
      result << "+#{mfirst}"
    end
    while original.length > 0
      ofirst, *original = original
      break if ofirst == sfirst
      result << "-#{ofirst}"
    end
    result << "#{sfirst}"
  end
  while modified.length > 0
    mfirst, *modified = modified
    result << "+#{mfirst}"
  end
  while original.length > 0
    ofirst, *original = original
    result << "-#{ofirst}"
  end
  return result
end

def pretty_diff(original, modified)
  subsequence = lcs(modified, original)
  diffs = find_diffs(original, modified, subsequence)

  puts 'ORIG      [' + original.join(', ') + ']'
  puts 'MODIFIED  [' + modified.join(', ') + ']'
  puts 'LCS       [' + subsequence.join(', ') + ']'
  puts 'DIFFS     [' + diffs.join(', ') + ']'
end

pretty_diff("human".scan(/./), "chimpanzee".scan(/./))
# ORIG      [h, u, m, a, n]
# MODIFIED  [c, h, i, m, p, a, n, z, e, e]
# LCS       [h, m, a, n]
# DIFFS     [+c, h, +i, -u, m, +p, a, n, +z, +e, +e]

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.