软工个人项目--论文查重
github作业
软工作业|作业要求
:--😐:--😐:--:
作业要求|论文查重
作业目标|论文查重算法设计+git代码管理+PSP表格+单元测试+性能测试
实现思路
假设序列S和T的长度分别为m和n, 两者的编辑距离表示为dp[m][n]. 则对序列进行操作时存在以下几种情况:
a.当S和T的末尾字符相等时, 对末尾字符不需要进行上述定义操作中(亦即"编辑")的任何一个, 也就是不需要增加计数. 则满足条件: dp[m][n] = dp[m-1][n-1].
b. 当S和T的末尾字符不相等时, 则需要对两者之一的末尾进行编辑, 相应的计数会增加1.
b1. 对S或T的末尾进行修改, 以使之与T或S相等, 则此时dp[m][n] = dp[m - 1][n - 1] + 1;
b2. 删除S末尾的元素, 使S与T相等, 则此时dp[m][n] = dp[m - 1][n] + 1;
b3. 删除T末尾的元素, 使T与S相等, 则此时dp[m][n] = dp[m][n - 1] + 1;
b4. 在S的末尾添加T的尾元素, 使S和T相等, 则此时S的长度变为m+1, 但是此时S和T的末尾元素已经相等, 只需要比较S的前m个元素与T的前n-1个元素, 所以满足dp[m][n] = dp[m][n - 1] + 1;
b5. 在T的末尾添加S的尾元素, 使T和S相等, 此时的情况跟b4相同, 满足dp[m][n] = dp[m - 1][n] + 1;
c. 比较特殊的情况是, 当S为空时, dp[0][n] = n; 而当T为空时, dp[m][0] = m; 这个很好理解, 例如对于序列""和"abc", 则两者的最少操作为3, 即序列""进行3次插入操作, 或者序列"abc"进行3次删除操作.

模块实现
Leven类中重要的函数:
- 
float getED(wstring str1, wstring str2, int len1, int len2);//用于计算句子最小编辑距离。
- 
void SentenceToOne();//循环按行文本读入,调用getED函数并将值压入vectoransArray中。 
- 
wstring UTF8ToUnicode(const string& str);//UTF-8文件读入数据流并转换成Unicode编码,有利于提高运行效率以及准确率。
main函数:
int main(int argc,char* argv[]) {  //argc为参数个数,命令行中文件路径会存在argv中。
	if (check(argc, argv)) {
		Leven leven;
		leven.init(argc,argv); 
		leven.Run();
	}
	
	system("pause");
	return 0;
}
检查命令行参数:
bool check(int argc, char* argv[]) {  //检查命令函参数
	if (argc != 4) {
		cout << "ERROR:参数错误!\n";
		return false;
	}
	if (_access(argv[1], 00) == -1 || _access(argv[2], 00) == -1) {
		if (_access(argv[1], 00) == -1) cout << "Refer Adress Error\n";
		if (_access(argv[2], 00) == -1) cout << "Test Adress Error\n";
		return false;
	}
	return true;
}
经典DP算法:
float Leven::getED(wstring str1, wstring str2, int len1, int len2) {
	int temp;
	vector<vector<int>> dp(len1+1, vector<int>(len2+1));//len1行len2列的二维数组,记录状态值。
	//初始化
	for (int i = 1; i <= len1; i++) {  //例dp[2][0]表示一个长度为2的字符串str1与一个空字符串str2的最小编辑距离为2。
		dp[i][0] = i;
	}
	for (int j = 1; j <= len2; j++) {
		dp[0][j] = j;
	}
	for (int i = 1; i <= len1; i++) {
		for (int j = 1; j <= len2; j++) {
			if (str2[j - 1] == str1[i - 1])
				dp[i][j] = dp[i - 1][j - 1];
			else {
				temp = min(dp[i][j - 1], dp[i - 1][j]);
				dp[i][j] = min(temp, dp[i - 1][j - 1]) + 1;  //因为不一样所以会在最小结果上+1
			}
		}
	}
	return dp[len1][len2];
}
性能测试
改进思路:
UTF-8文本读入数据流,字节占比不同,影响代码效率以及准确率,转换成Unicode编码。

未覆盖部分基本为控制异常代码。

运行结果展示
orig.txt--原文件 orig_0.8_add.txt--修改文件 answer.txt--存放查重率文件
单元测试
测试最小编辑距离,由于汉字的比较较难判断,因此都由英文、空格、逗号等代替。

测试在命令行传参数时,参数个数正确,路径不可访问时是否会传回布尔值否。

测试UTF8ToUnicode函数是否能够转换标点符号和空格。

异常处理
处理命令行输入异常:输入参数个数不对、输入路径不可访问。
bool check(int argc, char* argv[]) {  //检查命令函参数
	if (argc != 4) {
		cout << "ERROR:参数错误!\n";
		return false;
	}
	if (_access(argv[1], 00) == -1 || _access(argv[2], 00) == -1) {
		if (_access(argv[1], 00) == -1) cout << "Refer Adress Error\n";
		if (_access(argv[2], 00) == -1) cout << "Test Adress Error\n";
		return false;
	}
	return true;
}
库函数可能发生异常,所以要捕获。
wstring Leven::UTF8ToUnicode(const string& str) {  //进行文本编码转换,以加强准确度。
	wstring ans;
	try {
		wstring_convert< codecvt_utf8<wchar_t> > wcv;
		ans = wcv.from_bytes(str);
	}
	catch (const exception& e) {
		cerr << e.what() << endl;
	}
	return ans;
}
PSP表格:
| PSP2.1 | Personal Software Process Stages | 预估耗时(小时) | 实际耗时(小时) | 
|---|---|---|---|
| Planning | 计划 | 48h | 5h | 
| Estimate | 估计这个任务需要多少时间 | 2h | 3h | 
| Development | 开发 | 12h | 24h | 
| Analysis | 需求分析(包括学习新技术) | 8h | 10h | 
| Design Spec | 生成设计文档 | 4h | 3h | 
| Design Review | 设计复审 | 4h | 6h | 
| Coding Standard | 代码规范(为目前的开发制定合适的规范) | 4h | 6h | 
| Design | 具体设计 | 8h | 12h | 
| Coding | 具体编码 | 8h | 6h | 
| Code Review | 代码复审 | 2h | 4h | 
| Test | 测试(自我测试,修改代码,提交修改) | 12h | 27h | 
| Reporting | 报告 | 4h | 5h | 
| Test Report | 测试报告 | 6h | 4h | 
| Size Measurement | 计算工作量 | 3h | 5h | 
| Postmortem&Process Improvement Plan | 事后总结,并提出过程改进计划 | 4h | 2 h | 
| . | 合计 | 129h | 120h | 
个人项目总结
第一次尝试在较短的时间内实现算法、测试平台、代码托管等的综合使用,感觉还是比较刺激和紧迫的。最开始我选择的是基于最小编辑距离的论文查重,但是运行较慢,且文件数据流对比时比较死板,很难去除无关因素。因此我转向基于余弦相似算法,鉴于python第三方库jieba的体验感良好,因此想尝试python嵌入,搜索了很多资料,但是可能由于第三方库原因始终会被因为找不到脚本而中断。无意中发现github有人做了C++的jieba库,但是体验感不是很好,光是一开始的初始化就需要长达半分多钟,且分词简陋,仅仅是将中文拆成一个个文字。最终还是老老实实的优化一开始的算法,基于最小编辑距离的论文查重。
在算法中,通过读取文件的每一行进行对比求出句子相似度,最后除以比较的句子总数来计算的查重率,这一想法启发于Paperpass。在优化上,将UTF-8编码的格式转换为Unicode的统一编码,能方便比较和提高准确率。
对此次个人项目的想法改进,此基础上实现动态DP算法。再次尝试提取句子中的关键字,采用余弦相似算法。







 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号