简介:SIMGUI是一款基于Electron与Element UI开发的C++/Python代码查重工具,核心集成SIM相似性检测算法,无需了解算法底层实现即可通过图形界面完成查重,可快速定位源码中重复或相似片段。适用于课程作业查重、毕业设计审查、代码评审和团队协作等场景,能有效防范抄袭风险,也为后续代码重构与质量优化提供依据。资源包共87个文件,约69.94MB,其中exe提供主程序入口,dll承载运行依赖,pak与asar保存界面语言和核心逻辑,png为操作示意截图,另附license授权信息;免安装版解压即可使用,无需手动搭建Electron或编译环境。已有529人学习/下载。使用时支持导入代码文件,调整灵敏度及忽略大小写、空格、注释等参数,检测结果以可视化形式列出相似代码块,便于逐段查看对比并导出报告,帮助开发者快速梳理重复逻辑、保障项目代码质量,尤其适合教学、科研与团队协作中的代码规范性检查。
1. 免安装的 SIMGUI:C++ 和 Python 代码查重,从双击 exe 开始
SIMGUI 是一款把开源 SIM 算法封装进图形界面的代码查重工具,双击「代码查重.exe」就能跑,不需要装 Python 环境,也不用配编译器和 Node.js,界面里点几下就能对 C++ 和 Python 源码做相似度检测。这篇笔记我会从它的 Electron 免安装包结构拆起,讲到实际查重时的参数选择,再列出几个我踩过的坑,最后给一套「初筛 + 人眼复核」的验证方法,帮你判断哪些结果是真想抄、哪些只是模板撞车。
适合三类人:收了 40 份课程作业但没时间逐对比对的高校老师;在团队评审里想快速定位重复模块的工程师;交作业前想自查一遍代码的学生。资源本体就是标题里那个 zip,解压即用,前提是别只拷 exe 出来,整个目录都得留着。
2. 免安装包拆解:Electron 外壳、SIM 内核与那 50 个语言包各自干什么
解开压缩包后,我的第一反应不是双击 exe,而是先看目录结构。这一眼扫过去,典型的 Electron 打包产物:一个几十 MB 的 exe,一堆 .pak 语言包,还有 v8 快照和 Chromium 依赖库。把外壳认清楚,后面遇到「双击没反应」「杀软报警」「界面乱码」时,才知道该去查哪一层。
2.1 SIM 算法:为什么它抓的是「结构」而不是「字符」
SIM 是一套用了很多年的开源代码相似度检测算法,和文本 diff 最大的差别在于输入粒度。diff 比较的是字符流、行流,而 SIM 先把源码切成一串 token:int count = 0;会被拆成关键字int、标识符count、运算符=、数字0、分号这几个最小单元,再在 token 序列里找最长相似子串。
这种做法的直接收益是:学生把student_count改成n,把while (i < n)改成for (i = 0; i < n; i++),文本 diff 会报出一堆变更,但 SIM 眼里核心 token 结构没变,照样能命中。反过来,如果只是换行缩进、变量改名、插入注释,也不会被文本级噪音掩盖。这就是它比直接比对文本更适合查作业的原因。
代价同样明显。SIM 不关心语义,把整个函数换一种完全不同的写法重构后再抄核心逻辑,它基本抓不到;而且它对「公共模板代码」没有豁免能力,课件里给的框架会被当成每个学生都「抄」了一遍。这点会在第 4 章和第 5 章反复提到,也是所有基于 SIM 的工具共有的边界,不是 SIMGUI 特有的问题。
2.2 目录结构:每个文件是干什么的
这套免安装包解压后,文件大致分成四类,我整理了一张表:
| 文件/目录 | 角色 | 能删吗 |
|---|---|---|
| 代码查重.exe | Electron 主进程入口,双击启动 | 不删 |
| resources/app.asar | 应用本体压缩包,界面代码 + SIM 算法封装都在里面 | 不删 |
| 根目录下 SIM 相关文件 | 查重内核 | 不删 |
| snapshot_blob.bin / v8_context_snapshot.bin | V8 引擎启动快照 | 不删 |
| icudtl.dat | ICU 国际化字符数据 | 不删 |
| resources.pak / chrome_100_percent.pak / chrome_200_percent.pak | Chromium 界面资源 | 不删 |
| locales/*.pak 几十个语言包 | 各语言的界面翻译资源 | 可精简 |
| ffmpeg.dll / libGLESv2.dll / libEGL.dll / vk_swiftshader.dll / vulkan-1.dll / d3dcompiler_47.dll | Chromium 渲染、GPU 软件渲染与音视频依赖 | 不删 |
其中最关键的是resources/app.asar,Electron 把整个应用压缩进一个 asar 文件,免安装版其实就是把「Chromium + Node.js 运行时 + asar 应用」原封不动打成目录,所以才能做到不写注册表、不用装依赖。locales下那一大串 fi.pak、da.pak、et.pak、zh-CN.pak、en-US.pak 是 Chromium 的翻译资源,不是查重功能本身。手欠删了 zh-CN.pak,界面会退回英文;删掉其它语言基本无感。如果想让启动更快,只保留 zh-CN.pak 和 en-US.pak 通常没毛病。
v8_context_snapshot.bin和snapshot_blob.bin是 V8 引擎的启动快照,很多人瘦身免安装目录时喜欢见文件就删,这两个一删,exe 直接起不来。这是我想提醒的第一个翻车点,后面第 5 章还会展开讲。
提示:免安装版「绿色」的前提是三个东西同时在场:代码查重.exe、resources/app.asar、resources 目录。只拷一个 exe 到别的机器是跑不起来的。
2.3 免安装版和安装版怎么选
免安装版最有说服力的场景是机房和课堂答辩。教学查重经常发生在课程设计上机课、答辩现场,机器不一定有管理员权限,安装版要写注册表、装系统组件,还会被 UAC 弹窗拦一道;免安装版解压就能用,U 盘拔下来插哪都能跑。
代价也要讲清楚。免安装版没有自动更新,发布方出了新版本你得手动重新下载 zip;它不写注册表,所以「右键一键查重」、文件关联这类系统集成功能基本不要想;另外杀毒软件对未签名 Electron exe 的误报率明显高于正式安装版,这个在第 5.3 节单独说。
我的选择逻辑很简单:日常办公如果有安装版就装安装版,临时查重、机房答辩一律用免安装版,U 盘里常备一份 zip。两个不冲突,按场景切换即可。
3. 跑通一次查重:从导入代码到导出报告的五步操作
这章照着完整流程走一遍:导入代码 → 设置参数 → 执行查重 → 结果显示 → 导出报告。你跟着点完一轮,就知道这工具是不是你要的那种「能用」了。
3.1 导入代码:文件选择器的批量玩法
先准备一个专门放待查文件的目录。我强烈建议用纯英文路径,比如D:\sim_check,下面再按学号分文件夹。原因第 5 章会讲,你先把这当习惯立下来,后面能少很多莫名其妙的问题。
启动软件后,界面里通常有两个入口:一个是「导入文件」,适合只查三五份代码;另一个是「打开文件夹」,适合把整个目录递归加进来。收一个班 40 份作业的场景,直接点「打开文件夹」,选中D:\sim_check即可。
导入后先核对文件列表里的文件数和语言标记。C++ 和 Python 都能查,但 C++ 的扩展名要覆盖全:.cpp、.cc、.cxx、.h、.hpp。漏了 .cc 后缀,那一对文件会被静默跳过,相似度直接算作 0,这是很隐蔽的漏查。我一般会在导入前先跑一遍下面的 PowerShell,把待查清单列出来确认:
Get-ChildItem -Path "D:\sim_check" -Recurse -Include *.cpp,*.cc,*.cxx,*.h,*.hpp,*.py | Select-Object FullName, Length | Export-Csv -Path "D:\sim_check\files.csv" -Encoding UTF8这段命令做的事:-Include指定五类源码扩展名,把压缩包、说明文档、临时文件全挡在外面;Select-Object只挑文件路径和大小两个字段,导出的 files.csv 干净;Export-Csv方便你在 Excel 里打开。拿到清单后,重点看两类文件:Length 为 0 的空文件,以及路径里带中文的文件,这两类都是后面报错的高发对象。
3.2 设置参数:灵敏度、大小写、空格、注释的四组开关
SIMGUI 的查重参数直接继承自 SIM 的算法机制,理解「匹配粒度 + 忽略项」就能把它调明白,不用看底层实现。第一次跑,直接照这张表设:
| 参数 | 推荐初始值 | 说明 |
|---|---|---|
| 灵敏度/最小匹配长度 | 默认 | token 序列匹配长度下限,越小抓得越细、误报越多 |
| 忽略大小写 | 开 | 学生把StudentName改成studentname时能命中 |
| 忽略空格/换行 | 开 | 缩进差异对代码结构无意义 |
| 忽略注释 | 教学场景关掉 | 注释整段复制是常见的抄法,开着就漏了 |
「忽略大小写」有一个细节值得说:C++ 语言本身区分大小写,a和A是两个不同的标识符,但查重场景里我们要抓的是「改名字但结构照抄」的行为,所以忽略大小写反而合适。Python 同理,类名、函数名首字母大小写变体在抄作业里非常常见,开了不吃亏。
「忽略注释」不是无脑开的。很多人觉得注释不算代码,开了能减少干扰,但课程作业里,注释经常是整个函数被复制粘贴后唯一改动的部分。你把这个开关打开,就等于把「注释连抄」这一类直接放过了。我的习惯是第一次查重关掉忽略注释,等人眼把重复段落看一遍,再决定要不要开着重跑一次去抓纯代码部分。
3.3 执行查重:进度、文件对数量与预期耗时
点「开始检测」后,界面会列出正在比较的文件对。一次查重的工作量是组合数级别:40 个文件要比较 780 对,100 个文件是 4950 对。Python 由于要处理动态类型,同样文件量下通常比 C++ 稍慢,几百行的脚本没什么感觉,几千行的文件就能看出差距。
这阶段不用一直盯着进度条。等结果刷新后,界面上会出现一张按相似度降序排列的列表,每一行是一对文件。点开任意一行,能看到两个文件的相似段高亮,左右两栏对照,滚动条一拉就能从第一处匹配看到最后。
3.4 结果解读:从相似度到「是否实锤」的判断区间
SIMGUI 给出的是一个百分比,但我一般不把单个百分比当结论,而是先按区间分桶:
| 相似度 | 判断 | 后续动作 |
|---|---|---|
| 90% 以上 | 几乎实锤 | 人眼复核后可直接定性 |
| 70%~90% | 高度疑似 | 打开 diff 逐段确认 |
| 40%~70% | 有嫌疑,但可能是模板撞车 | 结合公共模板判断 |
| 40% 以下 | 一般不处理 | 跳过 |
注意一种常见误判:如果整份作业本身就只有 50 行,而课件提供的启动框架占了 45 行,那么哪怕学生自己的实现完全不抄,相似度也可能冲到 80% 以上。这不是工具算错了,是 SIM 把所有 token 一视同仁的结果。解决办法在第 5.5 节,思路是先把公共框架摘出去再查。
3.5 导出报告:文本和可视化页面
结果确认完后点导出。常见导出选项一般有两种:文本/CSV 报告和网页报告。CSV 适合拿回表格里做统计,字段就是文件 A、文件 B、相似度、匹配段信息;网页报告保留高亮和点击跳转,适合答辩现场放给评委老师看,比空口说「软件说他们相似」有说服力得多。
导出后我习惯先确认一次 CSV 的列名,后面第 4 章的排序脚本要用。不同版本导出的列名可能不一样,常见的是file_a/file_b/similarity,也有source/target/score这一套。先认清楚再写脚本,不然第 4 章的代码跑起来全是 KeyError。
4. 把参数调到能出活:降低误报率的三组组合与一个排序脚本
默认设置跑一遍,结果能用,但不好用。这一章的目标是把误报压到「人工复核成本可以接受」的程度,核心是三件事:两段式阈值、最小匹配长度、忽略项组合。
4.1 两段式阈值:先粗筛后精查
我跑查重从来都是两轮。第一轮把阈值调低,让相似度 30% 以上的文件对全部进列表,目的是不漏。第二轮再只盯着 70% 以上的人工复核。
为什么第一轮不直接设 70%?因为学生对查重工具有朴素认知,改注释、改变量名、拆行这些操作,会把实际 90% 的抄写压到 60%。如果第一轮阈值就设很高,这类「处理过的抄袭」直接被过滤掉了。粗筛阶段宁可多看 20 对,也不放走一对真的。
4.2 最小匹配长度与「撞车」:公共模板的分寸
灵敏度对应的底层参数是「最小匹配长度」:一段至少多少个 token 连续相同,才算一次有效匹配。设得越小,零散的公共片段——比如所有 C++ 作业都会有的#include <iostream>、using namespace std;——也会被计分,误报率直线上升;设得太大,短函数和表达式级别的抄写会被放过。
给一个通用起点:C++ 设 8~12,Python 设 6~10。如果你的作业是一堆 20 行的小脚本,长度往下降一档;如果是几百行的大项目,往上升一档。跑两遍对比误报率,几分钟就出结果,值得多试两组参数再定。这工具最大的优点就是快,调参成本很低。
4.3 忽略项组合的场景对照
不同使用场景,忽略项的选择完全不同,我按三种高频场景列了一张表:
| 场景 | 忽略大小写 | 忽略空格 | 忽略注释 |
|---|---|---|---|
| 课程作业反抄袭 | 开 | 开 | 关,防注释整段抄 |
| 团队代码重复模块检测 | 开 | 开 | 开,业务注释不同很正常 |
| 开源代码协议合规自查 | 开 | 开 | 开,侧重代码本体 |
团队检测和课程查重的需求是反的:团队里注释不同并不代表抄,而课程里注释连抄是重灾区。所以别把一套参数用到所有场景,先想清楚你查重是要给谁看、防什么行为。
4.4 给导出的报告排序:一个圈出 70% 以上文件对的脚本
SIMGUI 导出 CSV 之后,按相似度排序是基本操作,我一般直接用 Python 处理:
import csv with open('report.csv', 'r', encoding='utf-8') as f: rows = list(csv.DictReader(f)) hot = [] for row in rows: try: sim = float(row['similarity'].strip('%')) except (KeyError, ValueError): continue if sim >= 70: hot.append((sim, row['file_a'], row['file_b'])) hot.sort(reverse=True) for sim, a, b in hot: print(f'{sim:6.1f}% {a} <-> {b}')逻辑说明:csv.DictReader把每行读成字典,字段名直接对应表头,CSV 列顺序变了也不影响;float(row['similarity'].strip('%'))把「85.2%」转成数值,strip('%')去掉百分号,万一某行没有这个字段,KeyError或ValueError会被捕获跳过,不会让整个脚本崩掉;hot.sort(reverse=True)从高到低排序,最后用格式化字符串对齐输出。
常见改动点:如果导出列名是source/target/score,把脚本里三个字段名换掉即可;如果 CSV 是 GBK 编码,把encoding改成'gbk';只想看 90% 以上的,把阈值 70 改成 90。
提示:这个脚本只做排序,不作裁决。自动化工具负责「圈嫌疑」,你负责「定案」,下结论前务必打开每一对文件人工确认真实代码。
5. 免安装版避坑手册:五个我实际遇到过的代码查重问题
这章全是实操里攒下来的坑。每一条都是「现象 → 原因 → 解决」三段式,按顺序排,遇到哪条直接对号入座。
5.1 中文目录导入后文件列表是空的
现象:双击 exe 正常,界面也能开,但打开D:\课程作业\第3次\这个目录后,文件列表一个都不显示,或者点了「开始检测」进度条一直不动。
原因:Electron 导入目录走的是 Chromium 的文件系统层,在部分 Windows 环境里,非 ASCII 路径会解析失败;免安装版又少了安装过程对路径的规范化,中文路径的编码不一致就直接翻车。
解决:把待查文件统一拷到纯英文路径下,比如D:\check_in\hw3,再重新导入。这个我在第 3.1 节开头就强调过,不是洁癖,是省时间。收作业时让学生用「学号_姓名_作业序号.zip」命名,解压后你按学号归到英文目录里,全程避开中文路径。
5.2 打开几百个文件的目录就卡死
现象:一次把整个课程项目根目录递归导入,里面混着 build 文件夹、node_modules、.git 这类几千个文件,界面在导入阶段就白屏转圈,点了没反应。
原因:软件把目录递归遍历和第一次索引进索引都放在主进程里,文件数量一上来,目录 IO 加 token 化把界面线程拖死了。Electron 的单个窗口也扛不住这种批量。
解决:先把 build、.git、node_modules 这类非源码目录排除掉。我一般是先在文件管理器里搜索*.cpp和*.py,把命中的文件复制到一个干净目录,再导入;或者用第 3.1 节的 PowerShell 命令先导出清单,对着清单删掉不需要查的路径再导入。单次导入控制在 100 个文件以内,超了分两批。
5.3 杀毒软件把「代码查重.exe」隔离
现象:解压 zip 后双击 exe 没反应,打开 Windows Defender 或第三方杀软的隔离区,发现「代码查重.exe」躺在里面。
原因:Electron 免安装版是「自包含运行时 + asar 包 + v8 快照」的结构,文件特征和很多自解压恶意软件相似;加上 exe 没有代码签名,杀软宁可错杀。这是 Electron 免安装版的通病,不是这一款软件特有的行为。
解决:解压前先把压缩包加入杀软信任区,或者解压后把整个文件夹加入排除项;如果发布方提供正式安装版,装安装版的误报率会低不少,因为安装器通常有签名。你自己写代码心里有数,但发到学生手里时,建议提前在群里说一句「杀软误报,加白名单即可」,不然第一节课就有一半人打不开。
5.4 Python 文件正常,但 C++ 中文注释乱码还拉高相似度
现象:Python 文件查重结果正常,C++ 文件里的中文注释显示成乱码,而且相似度被莫名抬高,注释写得完全不同的两份代码被判成相似。
原因:Windows 上老式编辑器保存的 C++ 源码是 GBK/GB2312 编码,软件内部统一按 UTF-8 解码,中文解错变成乱码后,token 序列里的注释内容全乱了,相似的假象就是这样产生的。
解决:先统一编码再查。批量转码用一段 Python 脚本:
from pathlib import Path for p in Path(r'D:\check_in\hw3').rglob('*'): if p.suffix.lower() not in {'.cpp', '.cc', '.h', '.hpp', '.py'}: continue raw = p.read_bytes() for enc in ('utf-8', 'gbk'): try: text = raw.decode(enc) break except UnicodeDecodeError: continue else: continue p.write_text(text, encoding='utf-8')逻辑说明:rglob('*')递归遍历目录下所有文件,按后缀过滤出源码文件;然后依次尝试 utf-8 和 gbk 解码,哪个成功用哪个,最后统一以 utf-8 写回。UnicodeDecodeError兜住两种编码都解不开的二进制文件,直接跳过。
注意:转换前先备份整个目录,这是批量覆盖操作,没有后悔药。我一般先复制一份带
_bak后缀的副本再跑脚本,转坏了随时回滚。
5.5 全班相似度都 90%:模板代码污染了结果
现象:作业是「基于老师给的工程模板填空」,查重一跑,几乎每个文件对都是 90%,前十页全是高分,真正抄写的文件对被淹没在列表深处。
原因:SIM 只比结构,不区分「这段代码是不是课件提供的公共底座」。模板在整个作业文本里占比越大,所有文件对之间的基础相似度就越高,学生个人实现的差异被稀释了。
解决:把模板部分先拆出去。导入前,把模板文件从待查目录里删掉或移到另一个目录,只留学生自行完成的部分;如果模板和学生实现混在同一个文件里,先人工把模板段删除再导入。查重永远是对「学生亲手写的那部分」做判断,而不是对整个压缩包做判断。这一条解决完,高分列表才会真正反映问题。
6. 进阶验证:用双人核对法把「疑似重复」落到报告里
6.1 为什么需要交叉验证
SIMGUI 给的是初筛结论,不是最终结论。它不区分「两人合作完成」「一人抄另一人」「都抄了第三方」这三种情况,但教学场景里这三类的定性完全不同,处理方式也完全不同。所以我现在的流程是:SIMGUI 先圈出嫌疑对,然后对每一对跑一个并排 diff,人眼确认命中段到底属于哪种性质。先圈嫌疑,再定性,最后才写结论。
6.2 把嫌疑对清单转成可读的 diff 证据
第 4.4 节的脚本输出的是疑似清单,这节把清单往下游接一步,直接生成并排对比的 diff 文本:
import csv import difflib def load(path): with open(path, 'r', encoding='utf-8', errors='replace') as f: return f.read().splitlines() with open('hot_pairs.csv', 'r', encoding='utf-8') as f: pairs = list(csv.DictReader(f)) for row in pairs: try: sim = float(row['similarity'].strip('%')) except (KeyError, ValueError): continue if sim < 70: continue a = load(row['file_a']) b = load(row['file_b']) diff = difflib.unified_diff( a, b, fromfile=row['file_a'], tofile=row['file_b'], n=2, ) print('\n'.join(diff))这段脚本的重点是errors='replace',读取时遇到解不开的字节直接用替换字符兜底,脚本不会在第一步就因编码中断;difflib.unified_diff的n=2控制上下文行数,n 越大越容易看到两边的完整语境,我一般用 2,既能看到上下文又不会刷屏;相似度低于 70% 的文件对直接跳过,避免无关内容淹没真结果。
输出就是标准 diff 文本,+和-行集中的位置就是实锤命中段。把这个 diff 截图放进评分记录或团队评审记录里,比一句「软件说他们相似99%」可信得多,因为看的人能直接看到重复的具体位置和行数。
另外建议把每对文件的匹配段数量也看一眼。有些人抄了一个 200 行的函数,相似度 72% 被排后面;另一些人抄了 20 个 3 行的小片段,相似度 68% 反而排更前。这时候按「命中段数量 × 命中段规模」做人工加权,比只看百分比更接近实际工作量。SIMGUI 导出的报告里通常带匹配段列表,导出来自己手算或者写个小脚本统计都可以。
从那以后,我每次收到作业压缩包,都强制走一遍这套流程:解压到纯英文目录、删掉模板与公共框架、SIMGUI 粗筛、脚本排序、diff 人眼复核,最后才在评分表里下结论。跑过两百多份作业,误伤为零;而最开始「对着百分比直接下结论」的那个时期,出过两三次让人脸红的误判。工具的作用是圈嫌疑,不是审判,把嫌疑交给自己的眼睛,这张报告才真正可信。希望帮到你。
本文还有配套的精品资源,点击获取