Confronta i file di codice sorgente, ignorando le differenze di formattazione (come spazi bianchi, interruzioni di riga, ...)


9

Sto cercando un'applicazione in grado di confrontare due fonti C ++ e trovare le differenze significative per il codice (per confrontare le versioni che potrebbero essere state riformattate in modo diverso). Come minimo, qualcosa che ha la capacità di ignorare le modifiche in spazi bianchi, tabulazioni e newline che non influiscono sulla funzionalità della sorgente (si noti che se una newline è considerata spazio bianco dipende dalla lingua , e C e C ++ lo fanno ). E, idealmente, qualcosa che può identificare esattamente tutte le differenze significative del codice. Sono sotto Ubuntu.

Secondo diff --help | grep ignoreme, mi aspettavo diff -bBwZdi fare ragionevolmente il lavoro (mi aspettavo di ottenere alcuni falsi negativi, che verranno affrontati in seguito). Tuttavia, non lo fa.

se ho i seguenti file con frammenti

test_diff1.txt

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

e test_diff2.txt

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

poi

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

invece di risultati vuoti.

L'uso di un formattatore di codice come "filtro" su entrambi gli input può filtrare queste differenze, ma quindi l'output risultante dovrebbe essere ricollegato agli input originali per la segnalazione finale delle differenze per mantenere il testo e i numeri di riga effettivi. Quindi l'obiettivo è raggiungibile senza la necessità di un compilatore correttamente ... Non so se qualcosa è disponibile, però.

L'obiettivo può essere raggiunto diff? Altrimenti, esiste un'alternativa (preferibilmente, per la riga di comando)?

Risposte:


6

È possibile utilizzare dwdiff. Da man dwdiff:

dwdiff - un programma diff delimitato da parole

Il programma è molto intelligente - vedi 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

Provalo 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

Quindi avviare il confronto:

$ 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

Si prega di notare 100% commonsopra.


1

Dubito che questo sia qualcosa che diff può fare. Se ci sono cambiamenti di spazio all'interno di una linea, allora funzionerà (o altri programmi simili come kompare). Nel peggiore dei casi, puoi fare una ricerca e sostituire e comprimere i caratteri di tabulazione, ecc. Ma ciò che stai chiedendo per gli spazi bianchi cambia oltre una linea ...

Avresti bisogno di un programma che capisca il linguaggio C ++. Si noti che tutte le lingue sono diverse e Python, in particolare, utilizza gli spazi bianchi per definire i blocchi di codice. In quanto tale, dubito che qualsiasi programma generale di tipo diff funzionerebbe con "qualsiasi" (o uno specifico) linguaggio di programmazione.

È possibile prendere in considerazione una sorta di parser per esaminare i due file di origine e quindi confrontare gli output di questo parser.

Questo va oltre il mio background, ma ti suggerisco di esaminare Lex e Yacc . Queste sono pagine di Wikipedia; potresti voler dare un'occhiata a questa pagina che fornisce una spiegazione concisa e un esempio.


Non penso di aver bisogno di qualcosa che capisca il C ++ in particolare (almeno per ignorare le differenze dovute alle newline), non ho bisogno di compilare i sorgenti. Deve solo differire in modo appropriato, indipendentemente dalla lingua. C'è in realtà un'altra risposta che suggerisce dwdiff. Devo ancora provarlo, ma l'esempio fornito sembra convincente.
sancho.s ReinstateMonicaCellio il

Lex / Yacc non compila il codice sorgente, di per sé. Lo separerebbe in token. Ad esempio, se avevi "int foo = 0" vs "int bar = 0", chiaramente foo e bar sono due parole diverse; ma nel contesto di un programma, sono in realtà identici. Se vuoi catturare somiglianze come questa, potresti aver bisogno di un qualche tipo di parser. Se non lo fai, allora davvero, il suggerimento dwdiff sembra molto valido. In bocca al lupo!
Ray,

0

In una situazione simile, quando avevo bisogno di confrontare due gitrami in modo agnostico di formattazione del codice, ho fatto questo:

  1. creato rami temporanei:

    $ git co feature-a
    $ git co -b 1
    $ git co feature-b
    $ git co -b 2
    
  2. formattato entrambi i rami 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. ha fatto il confronto effettivo:

    $ git diff -w -b 1 2
    

    ( -w -bconsente di ignorare la differenza di spazio, per ogni evenienza).

Si può preferire uncrustifysopra clang-format( uncrustify's mod_full_brace_ifpossono essere utilizzati per far rispettare l'inserimento / rimozione di parentesi graffe intorno a linea singola if' corpo s).

Inoltre, se GNU parallelnon è installato, usa xargs- fa lo stesso, ma un po 'più a lungo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.