Metin dosyaları arasında karakter düzeyinde fark elde etmek için 'diff' (veya başka bir şey) kullanma


93

İki satır farkı ve karakter farkı elde etmek için 'diff' kullanmak istiyorum. Örneğin şunları göz önünde bulundurun:

Dosya 1

abcde
abc
abcccd

Dosya 2

abcde
ab
abccc

Diff -u kullanarak şunu elde ederim:

@@ -1,3 +1,3 @@
 abcde
-abc
-abcccd
\ No newline at end of file
+ab
+abccc
\ No newline at end of file

Ancak bana sadece bu satırlarda değişiklik olduğunu gösteriyor. Görmek istediğim şey şuna benzer:

@@ -1,3 +1,3 @@
 abcde
-ab<ins>c</ins>
-abccc<ins>d</ins>
\ No newline at end of file
+ab
+abccc
\ No newline at end of file

Beni anlıyorsun.

Şimdi, belirli bir hattaki farkı işaretlemek / kontrol etmek için diğer motorları kullanabileceğimi biliyorum . Ama hepsini yapan tek bir araç kullanmayı tercih ederim.


2
karakter başına fark, sözcük bölme için hiçbir boşluk uygulanmayan CJK metinleri söz konusu olduğunda özellikle yararlıdır.
把 友情 留 在 无 盐

Yanıtlar:


76

Git'in bir kelime farkı vardır ve tüm karakterleri etkili bir şekilde kelimeler olarak tanımlamak size bir karakter farkı verir. Ancak, satırsonu değişiklikleri göz ardı edilir .

Misal

Bunun gibi bir depo oluşturun:

mkdir chardifftest
cd chardifftest
git init
echo -e 'foobarbaz\ncatdog\nfox' > file
git add -A; git commit -m 1
echo -e 'fuobArbas\ncat\ndogfox' > file
git add -A; git commit -m 2

Şimdi yap git diff --word-diff=color --word-diff-regex=. master^ masterve alacaksın:

git fark

Yeni satırların hem eklemelerinin hem de silmelerinin göz ardı edilirken, karakter düzeyinde hem eklemelerin hem de silmelerin nasıl tanındığına dikkat edin.

Ayrıca şunlardan birini denemek isteyebilirsiniz:

git diff --word-diff=plain --word-diff-regex=. master^ master
git diff --word-diff=porcelain --word-diff-regex=. master^ master

77
Hiç bir depo oluşturmanıza gerek yok, basitçe git diff herhangi iki dosyayı dosya sisteminizin herhangi bir yerinde verebilirsiniz ve çalışır. Emriniz bu şekilde benim için harika çalışıyor, bu yüzden teşekkürler! git diff --word-diff=color --word-diff-regex=. file1 file2
qwertzguy

1
Bu son derece yararlıdır! Yapabilirsem, bir yazılım geliştirici olarak bir kez + 1 ve bir yazar / yazar olarak iki kez daha +1 olurdu. Satırların makul derecede kısa olma eğiliminde olduğu koddan farklı olarak, makaleler / öyküler yazarken, her paragraf uzun bir sözcük sarılı satır biçimini alma eğilimindedir ve bu özellik, farkları görsel olarak kullanışlı hale getirir.
mtraceur

29
--no-indexGit deposu dışında benim için çalışmasını sağlamak için yukarıdaki @ qwertzguys yanıtına eklemem gerekiyordu . Yani:git diff --no-index --word-diff=color --word-diff-regex=. file1 file2
Nathan Bell

2
git diff genel ayarda çalışmaz: git diff --no-index --word-diff = color --word-diff-regex =. <(echo string1) <(echo string2) .. Hiçbir şey, ancak bu işe yarıyor: diff --color <(echo string1) <(echo string2).
mosh

1
@NathanBell Bir deponun --no-indexiçini de eklemem gerekiyor
JShorthouse

32

Kullanabilirsiniz:

diff -u f1 f2 |colordiff |diff-highlight

ekran görüntüsü

colordiffbir Ubuntu paketidir. Kullanarak kurabilirsiniz sudo apt-get install colordiff.

diff-highlightgit'ten (2.9 sürümünden beri). İçinde bulunur /usr/share/doc/git/contrib/diff-highlight/diff-highlight. Onu bir yere koyabilirsin $PATH.


6
colordiff, Mac için homebrew'de de mevcuttur:brew install colordiff
Emil Stenström

5
Mac'te Bulabileceğiniz diff-highlightiçinde$(brew --prefix git)/share/git-core/contrib/diff-highlight/diff-highlight
StefanoP

2
Git'i brew kullanarak kurmadıysanız - diff-highlightpython pip ile de kurulabilir - pip install diff-highlight(git, brew yoluyla kurulsa bile tercih ederim)
Yaron U.

22

Bunu programlı olarak yapmak istiyorsanız, Python'un difflib'i mükemmeldir . Etkileşimli kullanım için, vim'in diff modunu kullanıyorum (kullanımı kolay: sadece vim'i çağırın vimdiff a b). Ayrıca , bir diff aracından bekleyebileceğiniz hemen hemen her şeyi yapan Beyond Compare'i ara sıra kullanıyorum .

Bunu yararlı bir şekilde yapan herhangi bir komut satırı aracı görmedim, ancak Will'in de belirttiği gibi, difflib örnek kodu yardımcı olabilir.


1
Oh .. Daha standart bir şey umuyordum (gizli bir komut satırı argümanı gibi). En berbat şey, Beyond Compare 2'ye sahip olmam ve hatta diff'in dosyasına / konsoluna metin çıktısını destekliyor, ancak yine de yalnızca line-diff'leri içeriyor ve char-diff'leri değil. Kimsede başka bir şey yoksa python'a bakacağım.
VitalyB

6
Beni vimdiff ile tanıştırmak için +1. Varsayılan renkleri okunamaz buldum, ancak bunun için stackoverflow.com/questions/2019281/… adresinde bir çözüm buldum .
tanımlanmamış

18

cmpSolaris'te şu komutu kullanabilirsiniz :

cmp

İki dosyayı karşılaştırın ve eğer farklılarsa, farklı oldukları ilk bayt ve satır numarasını söyler.


2
cmp(en azından bazı) Linux dağıtımlarında da mevcuttur.
Jeff Evans

7
Ayrıca Mac OS X'te de kullanılabilir.
Eric R. Rath

Karakterler birden çok bayttan oluşabilir ve OP görsel bir karşılaştırma istedi.
Cees Timmerman

1
@CeesTimmerman: cmp, bayrakla görsel karşılaştırmaya izin verir -l -b.
Smar

10

Python, difflibsorunuzu yanıtlamaya yardımcı olabilecek uygun bir kitaplığa sahiptir .

Aşağıda difflibfarklı python sürümleri için kullanılan iki oneliner bulunmaktadır .

python3 -c 'import difflib, sys; \
  print("".join( \
    difflib.ndiff( \ 
      open(sys.argv[1]).readlines(),open(sys.argv[2]).readlines())))'
python2 -c 'import difflib, sys; \
  print "".join( \
    difflib.ndiff( \
      open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines()))'

Bunlar ile hareket etmek daha kolaydır bir kabuk takma adı olarak işe yarayabilir .${SHELL_NAME}rc.

$ alias char_diff="python2 -c 'import difflib, sys; print \"\".join(difflib.ndiff(open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines()))'"
$ char_diff old_file new_file

Ve bağımsız bir dosyaya koymak için daha okunabilir bir sürüm.

#!/usr/bin/env python2
from __future__ import with_statement

import difflib
import sys

with open(sys.argv[1]) as old_f, open(sys.argv[2]) as new_f:
    old_lines, new_lines = old_f.readlines(), new_f.readlines()
diff = difflib.ndiff(old_lines, new_lines)
print ''.join(diff)

Mükemmel bir gömlek. Değişmeyen satırları yok sayan yoğunlaştırılmış bir çıktıya sahip olmak güzel olurdu.
aidan.plenert.macdonald

6
cmp -l file1 file2 | wc

Benim için iyi çalıştı. Sonucun en soldaki sayısı, farklı olan karakterlerin sayısını gösterir.


1
Ya da sadece en soldaki numarası almak için:cmp -l file1 file2 | wc -l
Tony

5

Ayrıca , En Uzun ortak alt dizi algoritmasını kullanarak bu sorunu çözmek için kendi betiğimi yazdım .

Bu şekilde idam edilir

JLDiff.py a.txt b.txt out.html

Sonuç, kırmızı ve yeşil renkli html'dir. Daha büyük dosyaların işlenmesi üssel olarak daha uzun zaman alır, ancak bu, önce satır satır kontrol etmeden karakter karşılaştırmasına göre gerçek bir karakter yapar.


JLDiff'in pypy altında çok daha hızlı çalıştığını buldum.
Joshua

4

Renkli, karakter düzeyinde diff çıktıya

Aşağıdaki komut dosyası ve diff-vurgulama (git'in bir parçası olan) ile yapabilecekleriniz :

Renkli fark ekran görüntüsü

#!/bin/sh -eu

# Use diff-highlight to show word-level differences

diff -U3 --minimal "$@" |
  sed 's/^-/\x1b[1;31m-/;s/^+/\x1b[1;32m+/;s/^@/\x1b[1;34m@/;s/$/\x1b[0m/' |
  diff-highlight

(Kredi @ retracile cevabı için sedvurgulama)


Kabuk ekranında iyi bir fark gösterir, ancak bu farkı GVim'de nasıl görebilirim?
Hemant Sharma

1
Bu gerçekten bir gvim sorusu :). command | gvim -ne istersen yapacak.
Att Righ

Referans için farklı vurgulama git, yolunuzun bir parçası olarak dahil edilmiş ancak üzerine yerleştirilmemiş gibi görünür . Bunun yaşadığı makinemden biri /usr/share/doc/git/contrib/diff-highlight.
Att Righ

kırık bağlantı. Diff-vurgulamayı nasıl kurarım. Bir paket yöneticisinde görünmüyor.
Trevor Hickey

3

Python'un difflib'i bunu yapabilir.

Belgeler, sizin için örnek bir komut satırı programı içerir .

Tam format belirttiğiniz gibi değil, ancak ndiff-stil çıktısını ayrıştırmak veya gösteriminizi oluşturmak için örnek programı değiştirmek kolay olacaktır.


Teşekkürler! Ben inceleyeceğim. Daha standart bir şey umuyordum (gizli bir komut satırı argümanı gibi). Ama yine de iyi olabilir. Hiç kimsenin daha standart bir şeyi yoksa python'a bakacağım (öyle görünmese de).
VitalyB

2

İşte bir çevrimiçi metin karşılaştırma aracı: http://text-compare.com/

Farklı olan her bir karakteri vurgulayabilir ve geri kalanı karşılaştırmaya devam eder.


Bu, tek karakterler için seçenek olmadan satır düzeyinde farklar yapıyor gibi görünüyor. Karakterleri karşılaştırmasını nasıl sağlıyorsunuz?
Ejderha

Ah; farklı olan karakterleri vurgular. Ama yine de çizgi seviyesinde catdogve cat\ndogsadece cat
Dragon

1

Daha basit çözümün her zaman iyi bir çözüm olduğunu düşünüyorum. Benim durumumda, aşağıdaki kod bana çok yardımcı oluyor. Umarım başkalarına yardımcı olur.

#!/bin/env python

def readfile( fileName ):
    f = open( fileName )
    c = f.read()
    f.close()
    return c

def diff( s1, s2 ):
    counter=0
    for ch1, ch2 in zip( s1, s2 ):
        if not ch1 == ch2:
            break
        counter+=1
    return counter < len( s1 ) and counter or -1

import sys

f1 = readfile( sys.argv[1] )
f2 = readfile( sys.argv[2] )
pos = diff( f1, f2 )
end = pos+200

if pos >= 0:
    print "Different at:", pos
    print ">", f1[pos:end]
    print "<", f2[pos:end]

En sevdiğiniz terminalde aşağıdaki sözdizimi ile iki dosyayı karşılaştırabilirsiniz:

$ ./diff.py fileNumber1 fileNumber2

0

Dosyalarınızı Git'te tutarsanız, farklı vurgulama komut dosyasıyla sürümler arasında farklılık gösterebilirsiniz farklı satırları vurgulanmış olarak farklı satırlar gösterecek olan, farklı farklılık gösterebilirsiniz.

Ne yazık ki, yalnızca kaldırılan satır sayısı eklenen satır sayısıyla eşleştiğinde işe yarar - satırlar eşleşmediğinde saplama kodu vardır, bu nedenle muhtemelen gelecekte düzeltilebilir.


0

Tam bir yanıt değil, ancak cmp -lçıktı yeterince net değilse, şunu kullanabilirsiniz:

sed 's/\(.\)/\1\n/g' file1 > file1.vertical
sed 's/\(.\)/\1\n/g' file2 > file2.vertical
diff file1.vertical file2.vertical

OSX'te `` sed 's / (.) / \ 1 \' $ '\ n / g' file1> file1.vertical sed 's / \ (. \) / \ 1 \' $ '\ n / g kullanın 'dosya2> dosya2.vertical' '
mmacvicar

0

Bu cevapların çoğu bir Perl modülü olan diff-vurgu kullanımından bahsediyor . Ama bir Perl modülünü nasıl kuracağımı öğrenmek istemedim. Bu yüzden, kendi kendine yeten bir Perl betiği olması için birkaç küçük değişiklik yaptım.

Şunları kullanarak kurabilirsiniz:

▶ curl -o /usr/local/bin/DiffHighlight.pl \
   https://raw.githubusercontent.com/alexharv074/scripts/master/DiffHighlight.pl

Ve kullanım ( colordiffzhanxw'nin cevabında bahsedilen Ubuntu'ya sahipseniz):

▶ diff -u f1 f2 | colordiff | DiffHighlight.pl

Ve kullanım (yapmazsanız):

▶ diff -u f1 f2 | DiffHighlight.pl

0

ccdiffgörev için uygun ve özel bir araçtır. Örneğiniz şu şekilde görünüyor:

ccdiff örnek çıktısı

Varsayılan olarak, renk farklılıklarını vurgular, ancak renk desteği olmayan bir konsolda da kullanılabilir.

Paket, Debian'ın ana deposuna dahildir:

ccdiff, değişen çizgilerin içini de renklendiren renkli bir farktır.

İki dosya arasındaki farkı gösteren tüm komut satırı araçları, küçük değişiklikleri görsel olarak yararlı gösterme konusunda yetersiz kalıyor. ccdiff, diff --colorveya görünüm ve hissini vermeye çalışır colordiff, ancak renkli çıktının görüntüsünü renkli silinmiş ve eklenen satırlardan, değiştirilen satırlar içindeki silinmiş ve eklenen karakterler için renklere genişletir.

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.