Порівняйте файли вихідного коду, ігноруючи відмінності у форматі (наприклад, пробіли, рядки,…)


9

Я шукаю додаток, який може зіставити два джерела C ++ і знайти значущі коди відмінності (для порівняння версій, які, можливо, були переформатовані по-різному). Як мінімум, те, що має можливість ігнорувати зміни в пробілах, пробілах та нових рядках, які не впливають на функціональність джерела (зауважте, що чи вважається новий рядок пробілом, залежить від мови , а C і C ++ роблять це ). І в ідеалі - щось, що може визначити саме всі кодозначущі відмінності. Я перебуваю під Ubuntu.

Згідно diff --help | grep ignore, я розраховував diff -bBwZвиконати цю роботу розумно (я розраховував отримати помилкові негативи, з якими розглядатися пізніше). Тим не менш, це не так.

якщо у мене є такі фрагменти з фрагментами

test_diff1.txt

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

і test_diff2.txt

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

тоді

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

замість порожніх результатів.

Використання форматера коду як "фільтра" на обох входах може відфільтрувати ці відмінності, але тоді отриманий результат повинен бути прив'язаний до початкових входів для остаточного звітування про різниці, щоб зберегти фактичний текст та номери рядків. Тож мета досяжна без необхідності компілятора належним чином ... Я не знаю, чи є щось доступне.

Чи можна досягти мети diff? В іншому випадку, чи існує альтернатива (бажано, для командного рядка)?

Відповіді:


6

Можна використовувати dwdiff. Від man dwdiff:

dwdiff - програма з розмежуванням слова, що відрізняється

Програма дуже розумна - дивіться 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

Перевірте це за допомогою:

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

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

Потім запустіть порівняння:

$ 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

Зверніть увагу 100% commonвище.


1

Я сумніваюсь, що це може зробити різниця. Якщо в межах рядка є зміни простору, він буде працювати (або інші подібні програми, такі як kompare). У гіршому випадку, ви можете виконати пошук і заміну та згортання символів вкладки тощо. Але те, що ви просите про зміни білого простору за межами рядка ...

Вам потрібна програма, яка розуміє мову C ++. Зауважте, що всі мови різні, і Python, зокрема, використовує пробіл для визначення кодових блоків. Як такий, я сумніваюсь, що будь-яка загальна програма, що нагадує, працюватиме з "будь-якою" (або конкретною) мовою програмування.

Ви можете розглянути якийсь аналіз для проходження двох вихідних файлів, а потім порівняння результатів цього аналізатора.

Це поза моїм досвідом, але я пропоную вам заглянути в Лекса та Якка . Це сторінки Вікіпедії; Ви можете подивитися на цю сторінку, яка дає стисле пояснення та приклад.


Я не думаю, що мені потрібно щось, що особливо розуміє C ++ (принаймні, для ігнорування відмінностей через нові рядки), мені не потрібно збирати джерела. Потрібно лише відрізнятися належним чином, незалежно від мови. Насправді є ще одна відповідь, яка підказує dwdiff. Це все-таки доведеться перевірити, але наведений приклад виглядає переконливо.
sancho.s ReinstateMonicaCellio

Lex / Yacc сама по собі не компілює вихідний код. Це розділило б його на лексеми. Наприклад, якщо у вас було "int foo = 0" vs "int bar = 0", чітко foo та bar - це два різних слова; але в контексті програми вони фактично ідентичні. Якщо ви хочете знайти подібність, як ця, то вам може знадобитися якийсь парсер. Якщо цього не зробити, то дійсно пропозиція dwdiff здається дуже гарною. Удачі!
Рей

0

У подібній ситуації, коли мені потрібно було порівняти дві gitгілки в агностичному форматуванні коду, я зробив це:

  1. створили тимчасові відділення:

    $ git co feature-a
    $ git co -b 1
    $ git co feature-b
    $ git co -b 2
    
  2. відформатовано обидві гілки за допомогою 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. зробив фактичне порівняння:

    $ git diff -w -b 1 2
    

    ( -w -bдозволяє проігнорувати різницю в просторі, про всяк випадок).

Ви можете віддати перевагу uncrustifyнад clang-format( uncrustify's mod_full_brace_ifможе використовуватися для примусового вставки / зняття фігурних брекетів навколо однолінійного ifтіла).

Крім того, якщо GNU parallelне встановлений, використовуйте xargs- він робить те саме, але трохи довше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.