2021秋软工实践第一次个人编程作业

题目要求

基础要求:输出关键字统计信息
进阶要求:输出有几组switch case结构,同时输出每组对应的case个数
拔高要求:输出有几组if else结构
终极要求:输出有几组if,else if,else结构

任务分解

建立Git本地仓库
建立GitHub远程仓库并与本地仓库链接
制定代码规范
寻找解题思路
编写代码并进行测试
优化代码并上传本地仓库
编写博客

一、PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3060
Estimate估计这个任务需要多少时间7801080
Development开发--
Analysis需求分析 (包括学习新技术)120150
Design Spec生成设计文档--
Design Review设计复审 (和同事审核设计文档)--
Coding Standard代码规范 (为目前的开发制定合适的规范)3030
Design具体设计6060
Coding具体编码240300
Code Review代码复审120240
Test测试(自我测试,修改代码,提交修改)120150
Reporting报告3030
Test Report测试报告1515
Size Measurement计算工作量1515
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划3030
合计7801080

二、解题思路

1.基础要求

  • 刚拿到题目的时候,其实最头痛的是用命令行读入文件,百度完发现这部分其实并不难。
  • 然后是字符串分割,发现C++难以实现,最后无奈选择按行读入文件
  • 对于关键字的匹配,我选择的是逐字符匹配原则,选择了一个比较暴力的算法。
  • 后续的完善过程中,完成了注释和引号中的关键字排除

2.进阶要求

  • switch/case的统计相比之下就要简单很多了,我的做法大概是设置一个标志和一个计数数组,遇到switch标志加1,并将标志作为计数器下标,遇到case则计数。

3.拔高要求、终极要求

  • 虽然是两个等级,但是必须放在一起解决。我的做法就是重新制定一个关键词数组,只包含if else,同时将elseif作为一个新的关键词,重新按基础要求的关键词匹配原则筛出关键词。
  • 具体分辨拔高和终极要求的方法是申请一个栈,遇到if和elseif则入栈,遇到else时,若栈顶为if,则pop掉一个栈顶元素,若为elseif则pop掉两个栈顶元素。同时对应计数器加1。

三、流程图

1.代码组织流程图

开始
命令行读取文件路径和等级
按行读入文件并筛取关键字
按等级完成各种关键字的统计
输出

2.关键词统计

no
yes
yes
no
开始
按行读入文件获取字符串
EndOfFile
字符串与关键字数组key进行逐个比对
输出cnt
所读字符串是否含有关键字
计数器cnt++并将关键词存入match数组
continue

3.switch/case统计

no
yes
yes
no
yes
no
开始
读取match数组
i>match.lenth
读取字符串
输出cnt
是否为switch
标志flag++
是否为case
以flag为下标的cnt数组++

4.if-else / if-elseif-else统计

no
yes
yes
no
yes
no
开始
设置新的关键词数组并与输入进行比对,获取新的match数组
申请栈stack
i>match.lenth
读取字符串
输出cnt1/cnt2
是否if/elseif
入栈
栈顶元素是否为if
stack.pop,cnt1++
stack.pop,stack.pop,cnt2++

四、主要代码

1.字符串比对函数

int bruteforce(string t, string p) {	//按字符比对函数,参数分别为待比对字符串和模板字符串
	int lenT = t.size();
	int lenP = p.size();
	int i, j;

	for (i = 0; i <= lenT - lenP; ++i) {//循环遍历每个字符,
		for (j = 0; j < lenP; ++j) {	//以模板字符串长度遍历
			if (t[i + j] != p[j]) {		//存在不匹配字符,跳出循环
				break;
			}
		}
		if (t[i + j] == '/' || t[i + j] == '"')
			return 0;
		if (j == lenP && ((t[i - 1] < 'a' || t[i - 1]>'z') || (t[i + j + 1] < 'a' && t[i + j + 1]>'z')))		//排除注释和引号内容
			return 1;
	}
	return 0;
}

2.关键字统计函数

void readbyline(char** argv)		//读入命令行参数
{
	char buffer[256];
	fstream fFile(argv[1], ios::in | ios::out);	//读取文件
	while (!fFile.eof())
	{
		fFile.getline(buffer, 256, '\n');		//按行读取字符串
		int lenth = strlen(buffer);
		for (int i = 0;i < 31;i++) {
			if (bruteforce(buffer, key[i])) {	//调用比对函数
				match[cnt1] = key[i];
				cnt1++;
			}
		}
	}
	fFile.close();
}

3.switch/case统计函数

void level_2(string str[]) {		
	int temp1 = 0, temp2[100] = { 0 };
	int tmp = 0;
	for (int i = 0;i < cnt1;i++) {
		if (str[i] == "switch"){		//检测switch
			temp1++;					//switch数目
			tmp++;						//标志加1
		}

		else if (str[i] == "case")
			temp2[tmp]++;				//统计case
	}
}

4.统计if-else/if-elseif-else函数

void level_3and4(char** argv) {			
	level_2(match);
	int temp1 = 0, temp2 = 0;
	for (int i = 0;i < cnt2;i++) {
		if (if_match[i] == "if")
			stk.push(if_match[i]);				//为if则push进栈
		else if (if_match[i] == "else if" && stk.top() != "else if")	//栈顶为if时将elseif push进栈
			stk.push(if_match[i]);
		if (if_match[i] == "else" && stk.top() == "if") {
			stk.pop();							//检测到else时栈顶为if则pop一次
			if_cnt++;
		}
		else if (if_match[i] == "else" && stk.top() == "else if") {
			stk.pop();
			stk.pop();							//栈顶为elseif时pop两次
			elseif_cnt++;
		}
	}
}

五、单元测试和性能分析

在这里插入图片描述

六、本次作业总结

  • 这次作业对我来说完全是一个新的体验。包括git和GitHub的使用、对文件的读入以及IDE的一些使用等等,是我之前几乎从来没有接触过的东西。
  • 编写代码过程中遇到的最大的问题就是如何除去注释和引号中的关键字。由于我的代码采用的是逐字符比较,所以不管是正则表达式还是字符串分割,都没有效果。最后还是偷了一点懒,读到“ / ”和“ “ ”时,直接忽略。。虽然有点投机取巧,但还是有效果的。
  • 相比代码,各种工具还有性能测试、单元测试等等全新的名词才是真正花费时间的东西。一直到打完这篇博客之前,我都没有搞明白单元测试的原理。这是一个很可惜的地方,但由于ddl近在眼前,也只能不了了之。以后要是有空的话(一般没空 ),会继续研究的。
  • 总的来说,这是一次非常深刻的编程体验。这几天投入的时间很多,学到的东西也很多,同时也深刻意识到了自己的不足。不管是对于代码的规范性还是可读性,我感觉做的都还不够。包括IDE的使用等等,由于之前一直使用的是devc++,导致这次使用VS出现了很大的阻碍,在网络上学了好久,也没有完全搞明白VS的使用。总而言之,这次的作业真的让我收获良多
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值