Bandingkan file kode sumber, abaikan perbedaan pemformatan (seperti spasi putih, linebreak, ...)

9

Saya mencari aplikasi yang dapat membandingkan dua sumber C ++ dan menemukan perbedaan yang berarti kode (untuk membandingkan versi yang mungkin telah diformat ulang secara berbeda). Paling tidak, sesuatu yang memiliki kemampuan untuk mengabaikan perubahan dalam ruang putih, ruang tab dan baris baru yang tidak mempengaruhi fungsi sumber (perhatikan bahwa apakah baris baru dianggap sebagai spasi putih tergantung pada bahasa , dan C dan C ++ melakukannya ). Dan, idealnya, sesuatu yang dapat mengidentifikasi dengan tepat semua perbedaan yang bermakna kode. Saya di bawah Ubuntu.

Sebagai per diff --help | grep ignore, saya diharapkan diff -bBwZuntuk melakukan pekerjaan dengan wajar (saya berharap untuk mendapatkan beberapa negatif palsu, untuk ditangani nanti). Namun demikian, tidak.

jika saya memiliki file berikut dengan cuplikan

test_diff1.txt

    else if (prop == "P1") { return 0; }

dan test_diff2.txt

    else if (prop == "P1") {
        return 0;
    }

kemudian

$ diff -bBwZ test_diff1.txt test_diff2.txt
1c1,3
<     else if (prop == "P1") { return 0; }
---
>     else if (prop == "P1") {
>         return 0;
>     }

bukannya hasil kosong.

Menggunakan pemformat kode sebagai "filter" pada kedua input dapat menyaring perbedaan ini, tetapi kemudian output yang dihasilkan harus diikat kembali ke input asli untuk pelaporan akhir perbedaan untuk menjaga teks dan nomor baris yang sebenarnya. Jadi tujuannya dapat dicapai tanpa memerlukan kompiler dengan benar ... Saya tidak tahu apakah ada sesuatu yang tersedia.

Bisakah tujuan tercapai diff? Kalau tidak, apakah ada alternatif (lebih disukai, untuk baris perintah)?

sancho.s ReinstateMonicaCellio
sumber

Jawaban:

6

Anda bisa menggunakannya dwdiff. Dari man dwdiff:

dwdiff - program beda kata yang dibatasi

Program sangat pintar - lihat dwdiff --help:

$ dwdiff --help
Usage: dwdiff [OPTIONS] <OLD FILE> <NEW FILE>
-h, --help                             Print this help message
-v, --version                          Print version and copyright information
-d <delim>, --delimiters=<delim>       Specify delimiters
-P, --punctuation                      Use punctuation characters as delimiters
-W <ws>, --white-space=<ws>            Specify whitespace characters
-u, --diff-input                       Read the input as the output from diff
-S[<marker>], --paragraph-separator[=<marker>]  Show inserted or deleted blocks
                               of empty lines, optionally overriding the marker
-1, --no-deleted                       Do not print deleted words
-2, --no-inserted                      Do not print inserted words
-3, --no-common                        Do not print common words
-L[<width>], --line-numbers[<width>]   Prepend line numbers
-C<num>, --context=<num>               Show <num> lines of context
-s, --statistics                       Print statistics when done
--wdiff-output                         Produce wdiff compatible output
-i, --ignore-case                      Ignore differences in case
-I, --ignore-formatting                Ignore formatting differences
-m <num>, --match-context=<num>        Use <num> words of context for matching
--aggregate-changes                    Allow close changes to aggregate
-A <alg>, --algorithm=<alg>            Choose algorithm: best, normal, fast
-c[<spec>], --color[=<spec>]           Color mode
-l, --less-mode                        As -p but also overstrike whitespace
-p, --printer                          Use overstriking and bold text
-w <string>, --start-delete=<string>   String to mark begin of deleted text
-x <string>, --stop-delete=<string>    String to mark end of deleted text
-y <string>, --start-insert=<string>   String to mark begin of inserted text
-z <string>, --stop-insert=<string>    String to mark end of inserted text
-R, --repeat-markers                   Repeat markers at newlines
--profile=<name>                       Use profile <name>
--no-profile                           Disable profile reading

Uji dengan:

cat << EOF > test_diff1.txt
    else if (prop == "P1") { return 0; }
EOF

cat << EOF > test_diff2.txt
    else if (prop == "P1") {
        return 0;
    }
EOF

Kemudian luncurkan perbandingan:

$ dwdiff test_diff1.txt test_diff2.txt --statistics
    else if (prop == "P1") {
        return 0;
    }
old: 9 words  9 100% common  0 0% deleted  0 0% changed
new: 9 words  9 100% common  0 0% inserted  0 0% changed

Harap diperhatikan di 100% commonatas.

N0rbert
sumber
1

Saya ragu ini adalah sesuatu yang bisa dilakukan diff. Jika ada perubahan ruang dalam satu baris, maka itu akan berfungsi (atau program serupa lainnya seperti kompare). Lebih buruk lagi, Anda dapat melakukan pencarian-dan-ganti dan runtuhkan karakter tab, dll. Tapi apa yang Anda minta perubahan spasi putih di luar garis ...

Anda membutuhkan program yang mengerti bahasa C ++. Perhatikan bahwa semua bahasa berbeda dan Python, khususnya, menggunakan spasi untuk mendefinisikan blok kode. Karena itu, saya ragu program seperti umum akan bekerja dengan bahasa pemrograman "apa saja" (atau spesifik).

Anda mungkin mempertimbangkan beberapa jenis pengurai untuk pergi melalui dua file sumber dan kemudian membandingkan output pengurai ini.

Ini di luar latar belakang saya, tetapi saya sarankan Anda melihat ke Lex dan Yacc . Ini adalah halaman Wikipedia; Anda mungkin ingin melihat halaman ini yang memberikan penjelasan singkat dan contoh.

sinar
sumber
Saya tidak berpikir saya perlu sesuatu yang mengerti C ++ khususnya (setidaknya untuk mengabaikan perbedaan karena baris baru), saya tidak perlu mengkompilasi sumber. Itu hanya perlu berbeda secara tepat, apa pun bahasanya. Sebenarnya ada jawaban lain yang menunjukkan dwdiff. Masih harus mengujinya, tetapi contoh yang diberikan terlihat meyakinkan.
sancho.s ReinstateMonicaCellio
Lex / Yacc tidak mengkompilasi kode sumber, per se. Ini akan memisahkannya menjadi token. Misalnya, jika Anda memiliki "int foo = 0" vs "int bar = 0", jelas foo dan bar adalah dua kata yang berbeda; tetapi dalam konteks suatu program, mereka sebenarnya identik. Jika Anda ingin menangkap kesamaan seperti ini, maka Anda mungkin perlu semacam parser. Jika tidak, maka saran dwdiff sepertinya sangat bagus. Semoga berhasil!
Ray
0

Dalam situasi yang sama, ketika saya perlu membandingkan dua gitcabang dengan cara agnostik pemformatan kode, saya melakukan ini:

  1. membuat cabang sementara:

    $ git co feature-a
    $ git co -b 1
    $ git co feature-b
    $ git co -b 2
    
  2. memformat kedua cabang menggunakan clang-format:

    $ git co 1
    $ find . -name '*.cpp' -print0 | parallel -0 -n 1 clang-format -i -style=google
    $ git ci -a -m1 --no-verify
    $ git co 2
    $ find . -name '*.cpp' -print0 | parallel -0 -n 1 clang-format -i -style=google
    $ git ci -a -m2 --no-verify
    
  3. melakukan perbandingan aktual:

    $ git diff -w -b 1 2
    

    ( -w -bmemungkinkan Anda untuk mengabaikan perbedaan ruang, untuk berjaga-jaga).

Anda dapat memilih uncrustifylebih clang-format( uncrustify's mod_full_brace_ifdapat digunakan untuk menegakkan penyisipan / penghapusan kurung kurawal sekitar single-line if' s tubuh).

Juga, jika GNU paralleltidak diinstal, gunakan xargs- ia melakukan hal yang sama, tetapi sedikit lebih lama.

Andrey Starodubtsev
sumber