So sánh các tệp mã nguồn, bỏ qua các khác biệt về định dạng (như khoảng trắng, ngắt dòng, xóa)


9

Tôi đang tìm kiếm một ứng dụng có thể so sánh hai nguồn C ++ và tìm sự khác biệt có ý nghĩa mã (để so sánh các phiên bản có thể được định dạng lại khác nhau). Ở mức tối thiểu, một cái gì đó có khả năng bỏ qua các thay đổi trong khoảng trắng, không gian tab và dòng mới không ảnh hưởng đến chức năng của nguồn (lưu ý rằng một dòng mới được coi là khoảng trắng phụ thuộc vào ngôn ngữ và C và C ++ làm như vậy ). Và, lý tưởng nhất, một cái gì đó có thể xác định chính xác tất cả các khác biệt có ý nghĩa mã. Tôi đang dùng Ubuntu.

Theo diff --help | grep ignore, tôi dự kiến ​​sẽ diff -bBwZlàm công việc hợp lý (tôi dự kiến ​​sẽ nhận được một số tiêu cực sai, sẽ được xử lý sau). Tuy nhiên, nó không.

nếu tôi có các tệp sau với đoạn trích

test_diff1.txt

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

và test_diff2.txt

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

sau đó

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

thay vì kết quả trống rỗng.

Sử dụng một bộ định dạng mã làm "bộ lọc" cho cả hai đầu vào có thể lọc ra những khác biệt này, nhưng sau đó đầu ra kết quả sẽ phải được gắn lại với đầu vào ban đầu để báo cáo cuối cùng về sự khác biệt để giữ số văn bản và số dòng thực tế. Vì vậy, mục tiêu có thể đạt được mà không cần một trình biên dịch đúng cách ... Tuy nhiên, tôi không biết nếu có một cái gì đó có sẵn.

Mục tiêu có thể đạt được với diff? Nếu không, có một sự thay thế (tốt nhất là cho dòng lệnh)?

Câu trả lời:


6

Bạn có thể sử dụng dwdiff. Từ man dwdiff:

dwdiff - một chương trình khác biệt từ phân cách

Chương trình rất thông minh - xem 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

Kiểm tra nó với:

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

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

Sau đó khởi chạy so sánh:

$ 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

Xin lưu ý 100% commonở trên.


1

Tôi nghi ngờ đây là điều mà diff có thể làm. Nếu có thay đổi không gian trong một dòng, thì nó sẽ hoạt động (hoặc các chương trình tương tự khác như kompare). Tệ hơn nữa, bạn có thể thực hiện tìm kiếm và thay thế và thu gọn các ký tự tab, v.v. Nhưng những gì bạn đang yêu cầu thay đổi khoảng trắng ngoài một dòng ...

Bạn sẽ cần một chương trình hiểu ngôn ngữ C ++. Lưu ý rằng tất cả các ngôn ngữ là khác nhau và đặc biệt là Python sử dụng khoảng trắng để xác định khối mã. Như vậy, tôi nghi ngờ bất kỳ chương trình khác giống như chung nào cũng sẽ hoạt động với ngôn ngữ lập trình "bất kỳ" (hoặc cụ thể).

Bạn có thể xem xét một số loại trình phân tích cú pháp để đi qua hai tệp nguồn và sau đó so sánh các đầu ra của trình phân tích cú pháp này.

Điều này nằm ngoài lý lịch của tôi, nhưng tôi khuyên bạn nên tìm hiểu về LexYacc . Đây là những trang Wikipedia; bạn có thể muốn xem xét này trang đó cung cấp cho một lời giải thích ngắn gọn và một ví dụ.


Tôi không nghĩ rằng tôi cần một cái gì đó hiểu cụ thể về C ++ (ít nhất là để bỏ qua sự khác biệt do dòng mới), tôi không cần phải biên dịch các nguồn. Nó chỉ cần khác biệt thích hợp, bất kể ngôn ngữ. Thực sự có một câu trả lời khác cho thấy người lùn. Vẫn phải kiểm tra nó, nhưng ví dụ được cung cấp có vẻ thuyết phục.
sancho.s RebstateMonicaCellio

Lex / Yacc không biên dịch mã nguồn, mỗi lần. Nó sẽ tách nó thành mã thông báo. Ví dụ: nếu bạn có "int foo = 0" so với "int bar = 0", thì rõ ràng foo và bar là hai từ khác nhau; nhưng trong bối cảnh của một chương trình, chúng thực sự giống hệt nhau. Nếu bạn muốn bắt những điểm tương đồng như thế này, thì bạn có thể cần một số trình phân tích cú pháp. Nếu bạn không, thì thực sự, đề nghị người lùn có vẻ như là một điều rất tốt. Chúc may mắn!
Ray

0

Trong tình huống tương tự, khi tôi cần so sánh hai gitnhánh theo cách bất khả tri định dạng mã, tôi đã làm điều này:

  1. tạo các nhánh tạm thời:

    $ git co feature-a
    $ git co -b 1
    $ git co feature-b
    $ git co -b 2
    
  2. định dạng cả hai nhánh bằng cách sử dụng 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. đã so sánh thực tế:

    $ git diff -w -b 1 2
    

    ( -w -bcho phép bạn bỏ qua sự khác biệt về không gian, chỉ trong trường hợp).

Bạn có thể thích uncrustifyhơn clang-format( uncrustify's mod_full_brace_ifcó thể được sử dụng để thực thi chèn / loại bỏ các dấu ngoặc nhọn xung quanh single-line if' s cơ thể).

Ngoài ra, nếu GNU parallelkhông được cài đặt, hãy sử dụng xargs- nó cũng tương tự, nhưng lâu hơn một chút.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.