Menggunakan 'diff' (atau yang lainnya) untuk mendapatkan perbedaan level karakter antar file teks


91

Saya ingin menggunakan 'diff' untuk mendapatkan perbedaan garis antara dan perbedaan karakter. Misalnya, pertimbangkan:

File 1

abcde
abc
abcccd

File 2

abcde
ab
abccc

Menggunakan diff -u saya mendapatkan:

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

Namun, itu hanya menunjukkan kepada saya bahwa ada perubahan di baris ini. Yang ingin saya lihat adalah seperti ini:

@@ -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

Anda mengerti maksud saya.

Sekarang, saya tahu saya dapat menggunakan mesin lain untuk menandai / memeriksa perbedaan pada baris tertentu. Tapi saya lebih suka menggunakan satu alat yang melakukan semuanya.


2
per char diff sangat berguna terutama dalam hal teks CJK, di mana tidak ada spasi kosong yang diterapkan untuk pemisahan kata.
把 友情 留 在 无 盐

Jawaban:


75

Git memiliki kata diff, dan mendefinisikan semua karakter sebagai kata secara efektif memberi Anda perbedaan karakter. Namun, perubahan baris baru diabaikan .

Contoh

Buat repositori seperti ini:

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

Sekarang, lakukan git diff --word-diff=color --word-diff-regex=. master^ masterdan Anda akan mendapatkan:

git diff

Perhatikan bagaimana penambahan dan penghapusan dikenali pada tingkat karakter, sementara penambahan dan penghapusan baris baru diabaikan.

Anda mungkin juga ingin mencoba salah satu dari ini:

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

76
Anda tidak perlu membuat repo sama sekali, Anda cukup memberikan dua file pada git diff, dimanapun di sistem file Anda dan ini berfungsi. Dengan cara itu, perintah Anda bekerja dengan baik, jadi terima kasih! git diff --word-diff=color --word-diff-regex=. file1 file2
qwertzguy

1
Ini sangat membantu! Akan memberi +1 sekali sebagai pengembang perangkat lunak dan +1 dua kali lagi sebagai penulis / penulis jika saya bisa. Tidak seperti kode, di mana garis cenderung cukup pendek, saat menulis makalah / cerita, setiap paragraf cenderung berbentuk garis panjang yang dibungkus kata, dan fitur ini membuat perbedaan benar-benar berguna secara visual.
mtraceur

29
Saya perlu menambahkan --no-indexrespons @ qwertzguys di atas agar dapat berfungsi di luar git repo. Jadi:git diff --no-index --word-diff=color --word-diff-regex=. file1 file2
Nathan Bell

2
git diff tidak berfungsi dalam pengaturan umum: git diff --no-index --word-diff = color --word-diff-regex =. <(echo string1) <(echo string2) .. Tidak ada, tetapi ini berfungsi: diff --color <(echo string1) <(echo string2).
mosh

1
@NathanBell Saya perlu menambahkan --no-indexbagian dalam repo juga
JShorthouse

32

Kamu bisa memakai:

diff -u f1 f2 |colordiff |diff-highlight

tangkapan layar

colordiffadalah paket Ubuntu. Anda dapat menginstalnya menggunakansudo apt-get install colordiff .

diff-highlightberasal dari git (sejak versi 2.9). Itu terletak di /usr/share/doc/git/contrib/diff-highlight/diff-highlight. Anda dapat meletakkannya di suatu tempat di $PATH.


6
colordiff juga tersedia di homebrew untuk Mac:brew install colordiff
Emil Stenström

5
Di Mac, Anda dapat menemukannya diff-highlightdi$(brew --prefix git)/share/git-core/contrib/diff-highlight/diff-highlight
StefanoP

2
Jika Anda tidak menginstal git menggunakan brew - diff-highlightjuga dapat diinstal dengan pip python - pip install diff-highlight(Saya lebih suka bahkan jika git diinstal melalui brew)
Yaron U.

22

Difflib Python adalah ace jika Anda ingin melakukan ini secara terprogram. Untuk penggunaan interaktif, saya menggunakan mode diff vim (cukup mudah digunakan: cukup panggil vim dengan vimdiff a b). Saya juga terkadang menggunakan Beyond Compare , yang melakukan hampir semua yang Anda harapkan dari alat diff.

Saya belum melihat alat baris perintah yang melakukan ini dengan berguna, tetapi seperti yang dicatat oleh Will, kode contoh difflib mungkin membantu.


1
Oh .. Saya berharap untuk sesuatu yang lebih standar (seperti argumen baris perintah tersembunyi). Hal terkutuk adalah saya memiliki Beyond Compare 2 dan bahkan mendukung output teks ke file / konsol dari diff tetapi masih hanya menyertakan line-diffs dan bukan char-diffs. Saya akan memeriksa python jika tidak ada yang punya yang lain.
VitalyB

6
1 untuk memperkenalkan saya pada vimdiff. Saya menemukan warna default tidak dapat dibaca, tetapi menemukan solusi untuk itu di stackoverflow.com/questions/2019281/… .
tidak ditentukan

18

Anda dapat menggunakan cmpperintah di Solaris:

cmp

Bandingkan dua file, dan jika berbeda, beri tahu byte pertama dan nomor baris di mana mereka berbeda.


2
cmpjuga tersedia di (setidaknya beberapa) distribusi Linux.
Jeff Evans

7
Ini juga tersedia di Mac OS X.
Eric R. Rath

Karakter dapat terdiri dari beberapa byte, dan OP meminta perbandingan visual.
Cees Timmerman

1
@CeesTimmerman: cmp memungkinkan perbandingan visual, dengan bendera -l -b.
Smar

10

Python memiliki pustaka yang nyaman bernama difflibyang mungkin membantu menjawab pertanyaan Anda.

Di bawah ini adalah dua oneliners yang digunakan difflibuntuk versi python yang berbeda.

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()))'

Ini mungkin berguna sebagai alias shell yang lebih mudah untuk dipindahkan dengan file .${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

Dan versi yang lebih mudah dibaca untuk dimasukkan ke dalam file mandiri.

#!/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)

Satu liner yang luar biasa. Akan lebih baik jika memiliki keluaran kental yang mengabaikan baris yang tidak berubah.
aidan.plenert.macdonald

6
cmp -l file1 file2 | wc

Bekerja dengan baik untuk saya. Angka paling kiri dari hasil menunjukkan jumlah karakter yang berbeda.


1
Atau hanya untuk mendapatkan angka paling kiri:cmp -l file1 file2 | wc -l
Tony

5

Saya juga menulis skrip saya sendiri untuk menyelesaikan masalah ini menggunakan algoritma penerusan umum terpanjang.

Itu dijalankan seperti itu

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

Hasilnya dalam bentuk html dengan warna merah dan hijau. File yang lebih besar secara eksponensial membutuhkan waktu yang lebih lama untuk diproses tetapi ini melakukan perbandingan karakter demi karakter yang sebenarnya tanpa memeriksa baris demi baris terlebih dahulu.


Saya telah menemukan bahwa JLDiff berjalan jauh lebih cepat di bawah pypy.
Joshua

4

Berwarna, karakter tingkat diff ouput

Inilah yang dapat Anda lakukan dengan skrip di bawah ini dan diff-highlight (yang merupakan bagian dari git):

Screenshot diff berwarna

#!/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

(Kredit ke @ retracile ini jawaban untuk sedpenyorotan)


Ini menunjukkan perbedaan yang baik pada layar shell, tetapi bagaimana cara melihat perbedaan itu di GVim ??
Hemant Sharma

1
Apa itu benar-benar pertanyaan gvim :). command | gvim -akan melakukan apa yang kamu inginkan.
Att Righ

Untuk referensi, diff-highlight tampaknya disertakan sebagai bagian dari gittetapi tidak ditempatkan di jalur Anda. Satu mesin saya tempat ini tinggal /usr/share/doc/git/contrib/diff-highlight.
Att Righ

tautan rusak. Bagaimana cara menginstal diff-highlight. Sepertinya tidak berada di pengelola paket.
Trevor Hickey

3

Difflib Python dapat melakukan ini.

Dokumentasi tersebut menyertakan contoh program baris perintah untuk Anda.

Format persisnya tidak seperti yang Anda tentukan, tetapi akan sangat mudah untuk mengurai keluaran gaya ndiff atau memodifikasi program contoh untuk menghasilkan notasi Anda.


Terima kasih! Saya akan memeriksanya. Saya berharap untuk sesuatu yang lebih standar (seperti argumen baris perintah tersembunyi). Tapi itu mungkin masih baik-baik saja. Saya akan melihat python jika tidak ada yang lebih standar (meskipun sepertinya tidak).
VitalyB

2

Berikut adalah alat perbandingan teks online: http://text-compare.com/

Itu dapat menyorot setiap karakter yang berbeda dan terus membandingkan sisanya.


Ini tampaknya melakukan perbedaan tingkat baris tanpa opsi untuk karakter tunggal. Bagaimana Anda membuatnya membandingkan karakter?
Naga

Ah; itu menyoroti karakter yang berbeda. Tapi itu masih level garis catdogdan cat\ndoghanya akan cocokcat
Dragon

1

Saya pikir solusi yang lebih sederhana selalu merupakan solusi yang baik. Dalam kasus saya, kode di bawah ini sangat membantu saya. Saya harap ini membantu orang lain.

#!/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]

Anda dapat membandingkan dua file dengan sintaks berikut di terminal favorit Anda:

$ ./diff.py fileNumber1 fileNumber2

0

Jika Anda menyimpan file Anda di Git, Anda dapat membedakan versi dengan skrip diff-highlight , yang akan menampilkan baris yang berbeda, dengan perbedaan yang disorot.

Sayangnya ini hanya berfungsi ketika jumlah baris yang dihapus cocok dengan jumlah baris yang ditambahkan - ada kode rintisan ketika baris tidak cocok, jadi mungkin ini dapat diperbaiki di masa mendatang.


0

Bukan jawaban yang lengkap, tetapi jika cmp -lkeluarannya kurang jelas, Anda dapat menggunakan:

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

di OSX gunakan `` sed 's / (.) / \ 1 \' $ '\ n / g' file1> file1.vertical sed 's / \ (. \) / \ 1 \' $ '\ n / g 'file2> file2.vertical ``
mmacvicar

0

Sebagian besar jawaban ini menyebutkan penggunaan diff-highlight , sebuah modul Perl. Tetapi saya tidak ingin mengetahui cara menginstal modul Perl. Jadi saya membuat beberapa perubahan kecil untuk menjadi skrip Perl mandiri.

Anda dapat menginstalnya menggunakan:

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

Dan penggunaannya (jika Anda memiliki Ubuntu yang colordiffdisebutkan dalam jawaban zhanxw):

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

Dan penggunaannya (jika tidak):

▶ diff -u f1 f2 | DiffHighlight.pl
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.