ใช้ 'diff' (หรืออย่างอื่น) เพื่อให้ได้ระดับอักขระที่แตกต่างระหว่างไฟล์ข้อความ


93

ฉันต้องการใช้ 'diff' เพื่อให้ได้ทั้งความแตกต่างระหว่างบรรทัดและความแตกต่างของอักขระ ตัวอย่างเช่นพิจารณา:

ไฟล์ 1

abcde
abc
abcccd

ไฟล์ 2

abcde
ab
abccc

การใช้diff -uฉันได้รับ:

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

อย่างไรก็ตามมันแสดงให้ฉันเห็นว่ามีการเปลี่ยนแปลงในบรรทัดเหล่านี้เท่านั้น สิ่งที่ฉันอยากเห็นมีดังนี้:

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

คุณได้รับการล่องลอยของฉัน

ตอนนี้ฉันรู้ว่าฉันสามารถใช้เครื่องมืออื่นเพื่อทำเครื่องหมาย / ตรวจสอบความแตกต่างของบรรทัดเฉพาะได้ แต่ฉันอยากใช้เครื่องมือเดียวที่ทำได้ทั้งหมด


2
ต่อ char diff มีประโยชน์อย่างยิ่งเมื่อพูดถึงข้อความ CJK โดยที่ไม่มีช่องว่างใด ๆ สำหรับการแบ่งคำ
把友情留在无盐

คำตอบ:


76

Git มีความแตกต่างของคำและการกำหนดอักขระทั้งหมดเป็นคำอย่างมีประสิทธิภาพจะช่วยให้คุณมีอักขระที่แตกต่างกัน อย่างไรก็ตามการเปลี่ยนแปลงขึ้นบรรทัดใหม่จะถูกละเลย

ตัวอย่าง

สร้างที่เก็บดังนี้:

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

ตอนนี้ทำgit diff --word-diff=color --word-diff-regex=. master^ masterและคุณจะได้รับ:

ความแตกต่างของคอมไพล์

สังเกตว่าทั้งการเพิ่มและการลบได้รับการยอมรับในระดับอักขระในขณะที่ทั้งการเพิ่มและการลบบรรทัดใหม่จะถูกละเว้น

คุณอาจต้องการลองอย่างใดอย่างหนึ่งต่อไปนี้:

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

77
คุณไม่จำเป็นต้องสร้าง repo เลยเพียงแค่ให้ git diff สองไฟล์ใดก็ได้บนระบบไฟล์ของคุณและมันก็ใช้งานได้ คำสั่งของคุณใช้งานได้ดีสำหรับฉันในแบบนั้นขอบคุณมาก! git diff --word-diff=color --word-diff-regex=. file1 file2
qwertzguy

1
นี่เป็นประโยชน์อย่างยิ่ง! จะ +1 อีกครั้งในฐานะนักพัฒนาซอฟต์แวร์และ +1 อีกสองครั้งในฐานะผู้เขียน / นักเขียนถ้าทำได้ ซึ่งแตกต่างจากรหัสตรงที่บรรทัดมักจะสั้นพอสมควรเมื่อเขียนเอกสาร / เรื่องราวแต่ละย่อหน้ามักจะอยู่ในรูปแบบของบรรทัดที่มีคำยาว ๆ และคุณลักษณะนี้ทำให้ความแตกต่างมีประโยชน์อย่างแท้จริง
mtraceur

29
ฉันต้องการเพิ่ม--no-indexคำตอบของ @ qwertzguys ด้านบนเพื่อให้มันใช้งานได้สำหรับฉันนอก git repo ดังนั้น:git diff --no-index --word-diff=color --word-diff-regex=. file1 file2
Nathan Bell

2
git diff ไม่ทำงานในการตั้งค่าทั่วไป: git diff --no-index --word-diff = color --word-diff-regex = <(echo string1) <(echo string2) .. ไม่มีอะไร แต่ใช้งานได้: diff --color <(echo string1) <(echo string2)
mosh

1
@NathanBell ฉันต้องการเพิ่ม--no-indexภายใน repo ด้วย
JShorthouse

32

คุณสามารถใช้ได้:

diff -u f1 f2 |colordiff |diff-highlight

ภาพหน้าจอ

colordiffเป็นแพ็คเกจของ Ubuntu คุณสามารถติดตั้งโดยใช้sudo apt-get install colordiffไฟล์.

diff-highlightมาจาก git (ตั้งแต่เวอร์ชัน 2.9) ตั้งอยู่ใน/usr/share/doc/git/contrib/diff-highlight/diff-highlight. คุณสามารถวางไว้ที่ไหนสักแห่งใน$PATHไฟล์.


6
colordiff ยังมีอยู่ใน homebrew สำหรับ Mac:brew install colordiff
Emil Stenström

5
คุณสามารถค้นหาบน Mac ได้diff-highlightใน$(brew --prefix git)/share/git-core/contrib/diff-highlight/diff-highlight
StefanoP

2
ในกรณีที่คุณไม่ได้ติดตั้ง git โดยใช้ brew - diff-highlightสามารถติดตั้งด้วย pip ของ python ได้ - pip install diff-highlight(ฉันชอบแม้ว่าจะติดตั้ง git ผ่านทาง brew ก็ตาม)
Yaron U.

22

difflibของ Python คือเอซหากคุณต้องการทำสิ่งนี้โดยใช้โปรแกรม สำหรับการใช้งานแบบอินเทอร์แอกทีฟฉันใช้โหมด diff ของ vim (ใช้งานง่าย: เพียงแค่เรียกใช้ vim ด้วยvimdiff a b) ฉันยังใช้Beyond Compare ในบางโอกาสซึ่งทำทุกอย่างที่คุณคาดหวังได้จากเครื่องมือที่แตกต่าง

ฉันไม่เห็นเครื่องมือบรรทัดคำสั่งใด ๆ ที่ทำสิ่งนี้ได้อย่างมีประโยชน์ แต่ตามที่ Will บันทึกไว้โค้ดตัวอย่าง difflib อาจช่วยได้


1
โอ้ .. ฉันหวังว่าจะมีอะไรที่เป็นมาตรฐานมากขึ้น (เช่นอาร์กิวเมนต์บรรทัดคำสั่งที่ซ่อนอยู่) สิ่งที่เลวร้ายที่สุดคือฉันมี Beyond Compare 2 และยังรองรับเอาต์พุตข้อความไปยังไฟล์ / คอนโซลของ diff แต่ก็ยังรวมเฉพาะ line-diffs และไม่ char-diffs ฉันจะดูงูหลามถ้าไม่มีอะไรอื่น
VitalyB

6
+1 สำหรับการแนะนำให้ฉันรู้จัก vimdiff ผมพบว่าสีเริ่มต้นที่จะอ่านไม่ได้ แต่ก็พบว่าวิธีการแก้ปัญหาที่ที่stackoverflow.com/questions/2019281/...
ไม่ระบุ

18

คุณสามารถใช้cmpคำสั่งใน Solaris:

cmp

เปรียบเทียบไฟล์สองไฟล์หากแตกต่างกันให้บอกไบต์แรกและหมายเลขบรรทัดที่แตกต่างกัน


2
cmpยังมีให้ใช้งานบนลีนุกซ์ (อย่างน้อยบางรุ่น)
Jeff Evans

7
นอกจากนี้ยังมีให้บริการบน Mac OS X
Eric R. Rath

อักขระสามารถประกอบด้วยหลายไบต์และ OP ขอเปรียบเทียบภาพ
Cees Timmerman

1
@CeesTimmerman: cmp -l -bช่วยให้เปรียบเทียบภาพที่มีธง
Smar

10

Python มีไลบรารีที่สะดวกdifflibซึ่งอาจช่วยตอบคำถามของคุณได้

ด้านล่างนี้เป็นตัวดำเนินการสองตัวที่ใช้difflibสำหรับเวอร์ชัน python ที่แตกต่างกัน

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

สิ่งเหล่านี้อาจมีประโยชน์ในฐานะเชลล์นามแฝงซึ่งง่ายต่อการเคลื่อนย้ายด้วย.${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

และเวอร์ชันที่อ่านได้มากขึ้นเพื่อใส่ในไฟล์แบบสแตนด์อโลน

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

หนึ่งสมุทรที่ยอดเยี่ยม จะเป็นการดีที่จะมีเอาต์พุตแบบย่อที่ละเว้นบรรทัดที่ไม่เปลี่ยนแปลง
aidan.plenert.macdonald

6
cmp -l file1 file2 | wc

ทำงานได้ดีสำหรับฉัน ตัวเลขทางซ้ายสุดของผลลัพธ์ระบุจำนวนอักขระที่แตกต่างกัน


1
หรือเพียงแค่รับหมายเลขซ้ายสุด:cmp -l file1 file2 | wc -l
โทนี่

5

ฉันยังเขียนสคริปต์ของตัวเองเพื่อแก้ปัญหานี้โดยใช้อัลกอริธึมลำดับต่อมาที่ยาวที่สุด

มันถูกดำเนินการเช่นนี้

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

ผลลัพธ์คือ html ที่มีสีแดงและเขียว ไฟล์ขนาดใหญ่จะใช้เวลาในการประมวลผลนานขึ้นเป็นทวีคูณ แต่จะสร้างอักขระที่แท้จริงโดยการเปรียบเทียบอักขระโดยไม่ต้องตรวจสอบทีละบรรทัดก่อน


ฉันพบว่า JLDiff วิ่งเร็วกว่ามากภายใต้ pypy
Joshua

4

สีระดับตัวอักษร diff ouput

นี่คือสิ่งที่คุณสามารถทำได้ด้วยสคริปต์ด้านล่างและไฮไลต์ต่าง (ซึ่งเป็นส่วนหนึ่งของคอมไพล์):

ภาพหน้าจอสีต่างกัน

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

(ให้เครดิตกับคำตอบของ @ retracileสำหรับการsedเน้น)


มันแสดงความแตกต่างที่ดีบนหน้าจอเชลล์ แต่ฉันจะเห็นความแตกต่างใน GVim ได้อย่างไร?
ชาร์มา

1
สิ่งที่เป็นคำถาม gvim จริงๆ :) command | gvim -จะทำในสิ่งที่คุณต้องการ
Att Righ

สำหรับการอ้างอิงต่างไฮไลต์ดูเหมือนจะรวมเป็นส่วนหนึ่งgitแต่ไม่ได้วางไว้บนเส้นทางของคุณ /usr/share/doc/git/contrib/diff-highlightหนึ่งในเครื่องของฉันชีวิตนี้ได้ที่
Att Righ

ลิงค์เสีย ฉันจะติดตั้ง diff-highlight ได้อย่างไร ดูเหมือนจะไม่อยู่ในตัวจัดการแพ็คเกจ
Trevor Hickey

3

difflib ของ Python สามารถทำได้

เอกสารประกอบมีตัวอย่างโปรแกรมบรรทัดคำสั่งสำหรับคุณ

รูปแบบที่แน่นอนไม่ได้เป็นไปตามที่คุณระบุไว้ แต่จะตรงไปตรงมาที่จะแยกวิเคราะห์เอาต์พุตสไตล์ ndiff หรือแก้ไขโปรแกรมตัวอย่างเพื่อสร้างสัญกรณ์ของคุณ


ขอบคุณ! ฉันจะดูมัน ฉันหวังว่าจะมีบางสิ่งที่เป็นมาตรฐานมากขึ้น (เช่นอาร์กิวเมนต์บรรทัดคำสั่งที่ซ่อนอยู่) แต่มันอาจจะยังดี ฉันจะดู python ถ้าไม่มีใครมีมาตรฐานมากกว่านี้ (แม้ว่าจะดูเหมือนไม่ใช่ก็ตาม)
VitalyB

2

นี่คือเครื่องมือเปรียบเทียบข้อความออนไลน์: http://text-compare.com/

สามารถเน้นทุกตัวอักษรที่แตกต่างกันและเปรียบเทียบส่วนที่เหลือต่อไป


สิ่งนี้ดูเหมือนจะทำให้ระดับบรรทัดแตกต่างโดยไม่มีตัวเลือกสำหรับอักขระเดี่ยว เอาไปเปรียบเทียบตัวละครได้ยังไง?
Dragon

อา; มันเน้นตัวละครที่แตกต่างกัน แต่มันยังคงเป็นระดับไลน์ในนั้นcatdogและcat\ndogจะจับคู่ในcat
Dragon

1

ฉันคิดว่าวิธีแก้ปัญหาที่ง่ายกว่านั้นเป็นทางออกที่ดีเสมอ ในกรณีของฉันรหัสด้านล่างช่วยฉันได้มาก ฉันหวังว่ามันจะช่วยใครก็ได้

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

คุณสามารถเปรียบเทียบสองไฟล์กับไวยากรณ์ต่อไปนี้ได้ที่เทอร์มินัลที่คุณชื่นชอบ:

$ ./diff.py fileNumber1 fileNumber2

0

หากคุณเก็บไฟล์ไว้ใน Git คุณสามารถแตกต่างระหว่างเวอร์ชันต่างๆได้ด้วยสคริปต์ไฮไลต์ที่แตกต่างซึ่งจะแสดงบรรทัดที่แตกต่างกันโดยเน้นความแตกต่าง

น่าเสียดายที่จะใช้งานได้ก็ต่อเมื่อจำนวนบรรทัดที่ลบออกตรงกับจำนวนบรรทัดที่เพิ่มเท่านั้น - จะมีรหัส Stub สำหรับเมื่อบรรทัดไม่ตรงกันดังนั้นจึงน่าจะได้รับการแก้ไขในอนาคต


0

ไม่ใช่คำตอบที่สมบูรณ์ แต่หากcmp -lผลลัพธ์ไม่ชัดเจนเพียงพอคุณสามารถใช้:

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

บน OSX ให้ใช้ `` sed 's / (.) / \ 1 \' $ '\ n / g' file1> file1.vertical sed 's / \ (. \) / \ 1 \' $ '\ n / g 'file2> file2.vertical ``
mmacvicar

0

คำตอบเหล่านี้ส่วนใหญ่กล่าวถึงการใช้diff-highlightซึ่งเป็นโมดูล Perl แต่ฉันไม่ต้องการหาวิธีติดตั้งโมดูล Perl ดังนั้นฉันจึงทำการเปลี่ยนแปลงเล็กน้อยเพื่อให้เป็นสคริปต์ Perl ในตัว

คุณสามารถติดตั้งได้โดยใช้:

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

และการใช้งาน (หากคุณมี Ubuntu ที่colordiffกล่าวถึงในคำตอบของ zhanxw):

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

และการใช้งาน (ถ้าคุณไม่ทำ):

▶ diff -u f1 f2 | DiffHighlight.pl

0

ccdiffเป็นเครื่องมือเฉพาะที่สะดวกสำหรับงาน ตัวอย่างของคุณมีลักษณะดังนี้:

เอาต์พุตตัวอย่าง ccdiff

โดยค่าเริ่มต้นจะเน้นความแตกต่างของสี แต่สามารถใช้กับคอนโซลที่ไม่มีสีได้เช่นกัน

แพ็คเกจนี้รวมอยู่ในที่เก็บหลักของ Debian:

ccdiff คือความแตกต่างของสีที่ยังเปลี่ยนสีภายในเส้น

เครื่องมือบรรทัดคำสั่งทั้งหมดที่แสดงความแตกต่างระหว่างสองไฟล์นั้นขาดการแสดงการเปลี่ยนแปลงเล็กน้อยที่มีประโยชน์อย่างเห็นได้ชัด ccdiff พยายามให้รูปลักษณ์ของdiff --colorหรือcolordiffแต่ขยายการแสดงผลสีจากสีที่ถูกลบและเพิ่มเส้นเป็นสีสำหรับอักขระที่ถูกลบและเพิ่มภายในบรรทัดที่เปลี่ยนแปลง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.