プログラミングの課題を採点する関係で Python コードの類似性を計測したい状況が生じたので「source code similarity」でググてみたところ、以下のページを見つけた。
この中から以下の module を見つけた。
READEM に Compare to Moss とかいうセクションがあるんだけど、どうもこの分野では Moss ってのが有名なんだそうな。
ただし、Moss は Stanford で運営されてるインターネットサービスなんだそうで、無料で利用可能なのだけれど、アカウント申請がメールで問い合わせなのと、コードをサーバーに放り投げる必要があり、更に投げて解析した結果は公開され URL の秘匿のみで保護されるようなので、ちょっと使い辛い。
で、上記の pycode_similar をざっと見てみるととてもコンパクトなスクリプトになってて、どうも Python 標準ライブラリの ast モジュールを使って、AST (Absolute Syntax Tree: 抽象構文木) 構築して AST レベルで比較しているっぽい。
なんか ast.parse(python_source_code) でサクッと AST 構築出来てるの羨まし過ぎる。こういうモジュールが標準で附属してるのは Python 強い。
ここまで手軽だと他にもありそうなので、「python ast similarity」でググってみたら、以下のページを見つけた。
pycode_similar は 1:1 比較しかできないのに対して、pyastsim は任意の数のファイル与えて一気に総当たり検索してくれるので、よりお手軽度が高い。
とりあえず、どちらも AST レベルで比較することで、変数名の違いは無視して類似性を比較してくれて、
例えば、
と
は類似度 100% として以下のように認識される。
for ループ使ってるのに range() で降順に乗算してるのはちょっと独特だけど、まぁ典型的な書き方の範疇と言えなくはないし、仮に写したとしても申し訳程度に変数名は変えていてデッドコピーじゃないのでこれはまぁいいのかなとは思うが、どこで線を引くかは微妙である。
そういう微妙な判断は、コードの中身を目で見て比較しないと出来ないので、ちょっと面倒ではあるが仕方がないところ。
とりあえず、比較結果一覧から Graphical diff (meld や tkdiff, WinMerge 等) に食わせる UI あると捗りそうかな?
まじめにやるの面倒だけど、以下のような感じで、terminal 2 枚開いてコピペ方式だとコスト低いかな?
- GitHub / Topics / #code-similarity
この中から以下の module を見つけた。
- GitHub / fyrestone / pycode_similar
READEM に Compare to Moss とかいうセクションがあるんだけど、どうもこの分野では Moss ってのが有名なんだそうな。
ただし、Moss は Stanford で運営されてるインターネットサービスなんだそうで、無料で利用可能なのだけれど、アカウント申請がメールで問い合わせなのと、コードをサーバーに放り投げる必要があり、更に投げて解析した結果は公開され URL の秘匿のみで保護されるようなので、ちょっと使い辛い。
で、上記の pycode_similar をざっと見てみるととてもコンパクトなスクリプトになってて、どうも Python 標準ライブラリの ast モジュールを使って、AST (Absolute Syntax Tree: 抽象構文木) 構築して AST レベルで比較しているっぽい。
なんか ast.parse(python_source_code) でサクッと AST 構築出来てるの羨まし過ぎる。こういうモジュールが標準で附属してるのは Python 強い。
ここまで手軽だと他にもありそうなので、「python ast similarity」でググってみたら、以下のページを見つけた。
- PyPI / projects / pyastsim
pycode_similar は 1:1 比較しかできないのに対して、pyastsim は任意の数のファイル与えて一気に総当たり検索してくれるので、よりお手軽度が高い。
とりあえず、どちらも AST レベルで比較することで、変数名の違いは無視して類似性を比較してくれて、
例えば、
と
は類似度 100% として以下のように認識される。
$ pycode_similar a/factorial.py b/factorial.py ref: a/factorial.py candidate: b/factorial.py 100.00 % (18/18) of ref code structure is plagiarized by candidate. candidate function plagiarism details (AST lines >= 4 and plagiarism percentage >= 0.5): 1.0 : ref factorial<5:0>, candidate factorial<5:0>
$ pyastsim a/factorial.py b/factorial.py Detected pair similarity of 100% with edit distance of 0 for a/factorial.py and b/factorial.py
for ループ使ってるのに range() で降順に乗算してるのはちょっと独特だけど、まぁ典型的な書き方の範疇と言えなくはないし、仮に写したとしても申し訳程度に変数名は変えていてデッドコピーじゃないのでこれはまぁいいのかなとは思うが、どこで線を引くかは微妙である。
そういう微妙な判断は、コードの中身を目で見て比較しないと出来ないので、ちょっと面倒ではあるが仕方がないところ。
とりあえず、比較結果一覧から Graphical diff (meld や tkdiff, WinMerge 等) に食わせる UI あると捗りそうかな?
まじめにやるの面倒だけど、以下のような感じで、terminal 2 枚開いてコピペ方式だとコスト低いかな?
diffsim () { find . -iname "$1" -exec pyastsim "${OPT[@]}" {} + | sed -E 's@(.*) for ./(.*) and ./(.*)@meld "\2" \"\3" # \1@g;/^$/d' | grep -E '[0-9]*%|[0-9]*$'; }; OPT=( --threshold 0 ) ; diffsim factorial.py
試してはないけど、他にも PyPI で「plagia」で検索すると幾つか見つかる模様。
タグ
コメントをかく