web-dev-qa-db-ja.com

フォーマットの違い(空白、改行など)を無視して、ソースコードファイルを比較する

2つの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?で達成できますか?そうでなければ、代替手段があります行)?

9
sancho.s

dwdiffを使用できます。 man dwdiff から:

dwdiff-区切られたWord diffプログラム

プログラムは非常に賢い-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に注意してください。

6
N0rbert

これがdiffでできることだとは思いません。行内にスペースの変更がある場合、それは動作します(またはkompareのような他の同様のプログラム)。さらに悪いことに、タブ文字の検索と置換、折りたたみなどを行うことができます。しかし、空白を求めているのは行を超えて変化します...

C++言語を理解するプログラムが必要です。すべての言語は異なり、特にPythonは空白を使用してコードブロックを定義します。そのため、一般的なdiffのようなプログラムが「任意の」(または特定の)プログラミング言語で動作することを疑います。

何らかの種類のパーサーで2つのソースファイルを調べてから、このパーサーの出力を比較することを検討してください。

これは私の背景を超えていますが、 Lex および Yacc を検討することをお勧めします。これらはウィキペディアのページです。 this ページを見てください。簡潔な説明と例があります。

1
Ray

同様の状況で、コードフォーマットに依存しない方法で2つの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では、念のためスペースの違いを無視できます)。

clang-formatよりもuncrustifyを好む場合があります(uncrustifymod_full_brace_ifは、単一行ifの本体の周りに中括弧の挿入/削除を強制するために使用できます)。

また、GNU parallelがインストールされていない場合は、xargsを使用します。これは同じですが、少し長くなります。

0