Compare archivos de código fuente, ignorando las diferencias de formato (como espacios en blanco, saltos de línea, ...)

9

Estoy buscando una aplicación que pueda comparar dos fuentes de C ++ y encontrar las diferencias significativas en el código (para comparar versiones que pueden haber sido formateadas de manera diferente). Como mínimo, algo que tiene la capacidad de ignorar los cambios en los espacios en blanco, los espacios de tabulación y las nuevas líneas que no afectan la funcionalidad de la fuente (tenga en cuenta que si una nueva línea se considera espacio en blanco depende del idioma , y C y C ++ lo hacen) ) E, idealmente, algo que pueda identificar exactamente todas las diferencias significativas de código. Estoy bajo Ubuntu.

Según diff --help | grep ignorelo previsto, esperaba diff -bBwZhacer razonablemente el trabajo (esperaba obtener algunos falsos negativos, que se abordarán más adelante). Sin embargo, no lo hace.

si tengo los siguientes archivos con fragmentos

test_diff1.txt

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

y test_diff2.txt

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

entonces

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

en lugar de resultados vacíos.

El uso de un formateador de código como "filtro" en ambas entradas puede filtrar estas diferencias, pero luego la salida resultante tendría que estar vinculada a las entradas originales para el informe final de las diferencias para mantener el texto real y los números de línea. Por lo tanto, el objetivo es alcanzable sin la necesidad de un compilador correctamente ... Sin embargo, no sé si hay algo disponible.

¿Se puede alcanzar el objetivo diff? De lo contrario, ¿hay una alternativa (preferiblemente, para la línea de comando)?

sancho.s ReinstateMonicaCellio
fuente

Respuestas:

6

Puedes usar dwdiff. De man dwdiff:

dwdiff - un programa de diferencias de palabras delimitadas

El programa es muy inteligente - ver 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

Pruébalo con:

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

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

Luego inicie la comparación:

$ 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

Tenga en cuenta 100% commonarriba.

N0rbert
fuente
1

Dudo que esto sea algo que diff pueda hacer. Si hay cambios de espacio dentro de una línea, entonces funcionará (u otros programas similares como kompare). En el peor de los casos, puede hacer una búsqueda y reemplazar y colapsar caracteres, etc. Pero lo que está pidiendo para los espacios en blanco cambia más allá de una línea ...

Necesitaría un programa que entienda el lenguaje C ++. Tenga en cuenta que todos los lenguajes son diferentes y Python, en particular, utiliza espacios en blanco para definir bloques de código. Como tal, dudo que cualquier programa general similar a diff funcione con "cualquier" (o un lenguaje de programación específico).

Puede considerar algún tipo de analizador para revisar los dos archivos de origen y luego comparar las salidas de este analizador.

Esto está más allá de mis antecedentes, pero le sugiero que busque en Lex y Yacc . Estas son páginas de Wikipedia; es posible que desee echar un vistazo a esta página que ofrece una explicación concisa y un ejemplo.

Rayo
fuente
No creo que necesite algo que comprenda C ++ en particular (al menos para ignorar las diferencias debido a las nuevas líneas), no necesito compilar las fuentes. Solo necesita diferir adecuadamente, independientemente del idioma. En realidad, hay otra respuesta que sugiere dwdiff. Todavía tengo que probarlo, pero el ejemplo proporcionado parece convincente.
sancho.s ReinstateMonicaCellio
Lex / Yacc no compila el código fuente, per se. Lo separaría en fichas. Por ejemplo, si tenía "int foo = 0" vs "int bar = 0", claramente foo y bar son dos palabras diferentes; pero en el contexto de un programa, en realidad son idénticos. Si desea detectar similitudes como esta, es posible que necesite algún tipo de analizador. Si no lo hace, entonces, de hecho, la sugerencia dwdiff parece muy buena. ¡Buena suerte!
Ray
0

En una situación similar, cuando necesitaba comparar dos gitramas en forma agnóstica de formato de código, hice esto:

  1. ramas temporales creadas:

    $ git co feature-a
    $ git co -b 1
    $ git co feature-b
    $ git co -b 2
    
  2. formateó ambas ramas usando 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. hizo comparación real:

    $ git diff -w -b 1 2
    

    (le -w -bpermite ignorar la diferencia de espacio, por si acaso).

Puede preferir uncrustifysobre clang-format( se pueden usar uncrustify's mod_full_brace_ifpara forzar la inserción / eliminación de llaves alrededor del ifcuerpo de una sola línea ).

Además, si GNU parallelno está instalado, úselo xargs; hace lo mismo, pero un poco más.

Andrey Starodubtsev
fuente