一个简单的python代码剽窃检测工具
pycode-similar的Python项目详细描述
这是一个简单的python代码剽窃检测工具,其基本思想是规范python ast表示,并使用difflib获取从引用代码到候选代码的修改。pycode_similar中定义的剽窃是指候选代码剽窃了多少引用代码,这意味着交换引用代码和候选代码会得到不同的结果。
我只花了几个小时就实现了这个工具,所以要提高速度和准确性还有很长的路要走,但是它已经在检测我们公司新兵的家庭作业抄袭方面表现出色。
与苔藓相比
- 纯python实现
- 仅包含一个源文件
- 没有第三方依赖关系(使用treediff时zss除外)
- 无需注册moss账户
- 无需网络即可访问MOSS
这个工具在我知道有一个Moss (for a Measure Of Software Similarity)来确定程序的相似性之前就诞生了。我尝试了很多方法来注册斯坦福莫斯的账户,但仍然无法获得有效的账户。所以,我无法准确地比较pycode_similar和moss。
安装
如果时间不多,只需执行
$ pip install pycode_similar
它将在您的系统上安装模块(无需测试)。
另外,您可以复制并粘贴不需要第三方依赖的pycode_similar.py。
用法
如果pip安装正确,只需将其用作标准命令行工具。
$ pycode_similar usage: pycode_similar [-h] [-l L] [-p P] files files A simple plagiarism detection tool for python code positional arguments: files the input files optional arguments: -h, --help show this help message and exit -l L if AST line of the function >= value then output detail (default: 4) -p P if plagiarism percentage of the function >= value then output detail (default: 0.5) pycode_similar: error: too few arguments
当然,您也可以将其用作python库。
importpycode_similarpycode_similar.detect([referenced_code_str,candidate_code_str1,candidate_code_str2,...],diff_method=UnifiedDiff)
实施
该工具实现了两种diff方法:基于行的diff(unifieddiff)和基于树编辑距离的diff(treediff),这两种方法都在函数ast级运行。
- unifieddiff,diff规范化函数ast字符串行,简单但高效。
- treediff,diff函数ast,速度很慢,对小函数效果不好。(取决于zss)
所以,在cmd中运行这个工具时,默认的diff方法是unifieddiff。当你把它用作图书馆时,你可以切换到treediff。
测试
如果您有源代码,则可以使用
$ python pycode_similar/tests/test_cases.py
或执行
$ python pycode_similar.py pycode_similar/tests/original_version.py pycode_similar.py ref: tests/original_version.py candidate: pycode_similar.py 80.14 % (803/1002) of ref code structure is plagiarized by candidate. candidate function plagiarism details (AST lines >= 4 and plagiarism percentage >= 0.5): 1.0 : ref FuncNodeCollector._mark_docstring_sub_nodes<24:4>, candidate FuncNodeCollector._mark_docstring_sub_nodes<27:4> 1.0 : ref FuncNodeCollector._mark_docstring_nodes<54:8>, candidate FuncNodeCollector._mark_docstring_nodes<57:8> 1.0 : ref FuncNodeCollector.generic_visit<69:4>, candidate FuncNodeCollector.generic_visit<72:4> 1.0 : ref FuncNodeCollector.visit_Str<74:4>, candidate FuncNodeCollector.visit_Str<78:4> 1.0 : ref FuncNodeCollector.visit_Name<83:4>, candidate FuncNodeCollector.visit_Name<88:4> 1.0 : ref FuncNodeCollector.visit_Attribute<89:4>, candidate FuncNodeCollector.visit_Name<88:4> 1.0 : ref FuncNodeCollector.visit_ClassDef<95:4>, candidate FuncNodeCollector.visit_ClassDef<100:4> 1.0 : ref FuncNodeCollector.visit_FunctionDef<101:4>, candidate FuncNodeCollector.visit_FunctionDef<106:4> 1.0 : ref FuncInfo.__init__<141:4>, candidate FuncInfo.__init__<161:4> 1.0 : ref FuncInfo.__str__<151:4>, candidate FuncInfo.__str__<171:4> 1.0 : ref FuncInfo.func_code<162:4>, candidate FuncInfo.func_code<182:4> 1.0 : ref FuncInfo.func_code_lines<168:4>, candidate FuncInfo.func_code_lines<188:4> 1.0 : ref FuncInfo.func_ast<174:4>, candidate FuncInfo.func_ast<194:4> 1.0 : ref FuncInfo.func_ast_lines<180:4>, candidate FuncInfo.func_ast_lines<200:4> 1.0 : ref FuncInfo._retrieve_func_code_lines<186:4>, candidate FuncInfo._retrieve_func_code_lines<206:4> 1.0 : ref FuncInfo._iter_node<208:4>, candidate FuncInfo._iter_node<228:4> 1.0 : ref FuncInfo._dump<232:4>, candidate FuncInfo._dump<252:4> 1.0 : ref FuncInfo._inner_dump<242:8>, candidate FuncInfo._inner_dump<262:8> 1.0 : ref ArgParser.error<267:4>, candidate ArgParser.error<291:4> 0.95: ref unified_diff<281:0>, candidate UnifiedDiff._gen<339:8> 0.92: ref FuncNodeCollector.__init__<18:4>, candidate FuncNodeCollector.__init__<20:4> 0.92: ref FuncNodeCollector.visit_Compare<108:4>, candidate FuncNodeCollector._simple_nomalize<117:8> 0.89: ref FuncNodeCollector.visit_Expr<79:4>, candidate FuncNodeCollector.visit_Expr<83:4>
单击here 若要查看此差异->;0.92:ref funcnodecollector。请访问候选funcnodecollector的“比较”<;108:4>;。\u简单的“正常化”<;117:8>;