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

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? Иначе есть ли альтернатива (желательно для командной строки)?

sancho.s ReinstateMonicaCellio
источник

Ответы:

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выше.

N0rbert
источник
1

Я сомневаюсь, что это то, что может сделать diff. Если в строке есть пробелы, она будет работать (или другие подобные программы, такие как kompare). В худшем случае, вы можете выполнять поиск и замену и свертывать символы табуляции и т. Д. Но то, что вы просите для пробелов, меняется за пределы строки ...

Вам нужна программа, которая понимает язык C ++. Обратите внимание, что все языки различны, и Python, в частности, использует пробелы для определения блоков кода. Поэтому я сомневаюсь, что любая общая программа, похожая на diff, будет работать с «любым» (или конкретным) языком программирования.

Вы могли бы рассмотреть какой-то синтаксический анализатор, чтобы пройти через два исходных файла и затем сравнить выходные данные этого синтаксического анализатора.

Это за пределами моего опыта, но я предлагаю вам взглянуть на Лекса и Яка . Это страницы Википедии; Возможно, вы захотите взглянуть на эту страницу, которая дает краткое объяснение и пример.

луч
источник
Я не думаю, что мне нужно что-то, что понимает C ++, в частности (по крайней мере, для игнорирования различий из-за перевода строки), мне не нужно компилировать исходники. Нужно только дифференцировать соответственно, независимо от языка. На самом деле есть другой ответ, который предлагает dwdiff. Все еще предстоит проверить его, но приведенный пример выглядит убедительно.
sancho.s ReinstateMonicaCellio
По сути, Lex / Yacc не компилирует исходный код. Было бы разделить его на токены. Например, если у вас было «int foo = 0» против «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- он делает то же самое, но немного дольше.

Андрей Стародубцев
источник