• 软件工程个人项目


    软件工程个人项目

    1.Github项目地址

    https://github.com/AMzzcc/WCSimulation

    2.开发预计时间

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划
    Estimate 估计这个任务需要多少时间 15 15
    Development 开发
    Analysis 需求分析(包括学习新技术) 40 50
    Design Spec 生成设计文档 20 15
    Design Review 设计复审(和同事审核设计文档) 5 5
    Coding Standard 代码规范(为目前的开发置顶合适的规范) 5 5
    Design 具体设计 10 10
    Coding 具体编码 40 35
    Code Review 代码复审 20 15
    Test 测试(自我测试,修改代码,提交修改) 40 50
    Reporting 报告
    Test Report 测试报告 10 10
    Size Measurement 计算工作量 5 5
    Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 10 10
    Total 合计 220 225

    3.解题思路描述

    实现功能如下:

    基本功能列表:

    1. -c file.c //返回文件 file.c 的字符数

    2. -w file.c //返回文件 file.c 的词的数目

    3. -l file.c //返回文件 file.c 的行数

    扩展功能:

    1. -a 返回更复杂的数据(代码行 / 空行 / 注释行)。

    高级功能:

    1. 基本的Windows GUI 程序操作

    2. -x 支持通过图形界面选取文件

    -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

    编程语言选择:

    ​ 虽然觉得用C#可能会更方便些,但出于对语言的喜爱和挑战最终选择了C++

    功能所需知识分析:

    1. 基本功能和扩展功能属于算法问题,是对文件信息的计算。
    2. 如何在cmd运行exe时传入额外参数
    3. 如何通过API调用window的资源管理器选择文件来获取文件路径
    4. 如何使用C++进行文件读取
    5. 软件工程的单元测试等技能
    6. 采用QT的方式可以用C++编写图形化界面
    

    ​ 这其中关键的几点问题是:

    ​ 1.如何通过API调用window的资源管理器选择文件来获取文件路径,搜索花费了较长时间,筛选尝试了不少方式,

    ​ 2.图形化界面显示文件信息,想法是(1)采用QT的方式可以用C++编写图形化界面,但QT基本没使用过。(2)通过C#编写Unity的脚本来实现图形化界面,Unity是一个挺方便的游戏引擎,但最后由于时间不够只好放弃了

    ​ 3.软件工程相关技能的实践

    4.设计实现过程

    总体分析

    首先需要一个负责全过程的指挥官,然后输入字符串选择功能,读取字符串保存选择的功能,跳出文件管理器选择所选文件并获取地址,读取文件并进行文件信息的计算,最后输出文件信息。

    类,接口,结构体等设计

    WC

    1.负责指挥程序的全过程,调用其他封装好的类里的函数进行程序

    2.对错误信息进行检测和输出显示

    3.对最终计算的文件信息进行输出显示

    CommandProcess

    1.封装定义好指令信息结构体以及相关结构体

    2.处理输入指令,将其打包成指令信息结构体

    FIleProcess

    1.通过OPENFILENAME对话框调用window资源管理器选择文件

    2.获取文件路径并检查文件正确性

    class file
    {
    public:
    	string GetFilePathByGUI(CommandInfo commandInfo);
    	//获取文件并检查文件正确性
    
    private:
    	CString getFilePathByGUI();
    	//调用OPENFILENAME对话框
    };
    

    Function

    1.封装存放所有功能的实现函数供WC调用

    class function
    {
    public:
    	int CharacterCount();	//zifu
    	int WordCount();		//danci
    	int LineCount();		//hang
    	DLC DlcCount();			//kuozhan
    	function(CommandInfo commandInfo)
    	{
    		command_Info = commandInfo;
    	}
    private:
    	int characterCount(CommandInfo commandInfo);
    	int wordCount(CommandInfo commandInfo);
    	int lineCount(CommandInfo commandInfo);
    	DLC dlcCount(CommandInfo commandInfo);
    	CommandInfo command_Info;
    };
    

    接口

    int main(int argc, char* argv[]);	//负责接受额外传入参数
    void ErrorMessage(CommandInfo commandInfo);//输出错误信息
    void FileMessage(CommandInfo commandInfo, function Function); //输出文件信息
    

    结构体

    typedef struct 
    {
    public:
    	bool isError=false;				//是否出错
    	ErrorType errorType= noError;	 //错误类型
    	CommandType commandType;		//命令类型
    	string filePath;			    //文件地址
    	void HasError(ErrorType type)
    	{
    		isError = true;
    		errorType = type;
    	}
    }CommandInfo;						//指令信息结构体
    
    typedef struct
    {
    	bool c = false;
    	bool w = false;
    	bool l = false;
    	bool a = false;
    	bool x = false;
    }CommandType;						//指令类型结构体
    
    
    

    5.代码说明

    通过OPENFILENAME对话框调用window资源管理器选择文件

    CString file::getFilePathByGUI()
    {
    	CString path;
    	OPENFILENAME open;// 公共对话框结构。
    	char file[MAX_PATH];// 用来保存获取文件名称的缓冲区。 
    	ZeroMemory(&open, sizeof(OPENFILENAME)); // 初始化选择文件对话框
    	open.lStructSize = sizeof(OPENFILENAME);//指定这个结构的大小,以字节为单位。
    	open.lpstrFile = file;//打开的文件的全路径
    	open.lpstrTitle = "选择文件";//窗口的标题
    	open.lpstrFile[0] = ''; //第一个字符串是过滤器描述的显示字符串
    	open.nMaxFile = MAX_PATH;  //指定lpstrFile缓冲的大小,以TCHARs为单位
    	open.lpstrFilter = "文本文件(*.txt)*.txtC语言文件(*.c)*.c";  //打开文件类型
    	open.nFilterIndex = 1;  //指定在文件类型控件中当前选择的过滤器的索引
    	open.lpstrFileTitle = NULL; // 指向接收选择的文件的文件名和扩展名的缓冲(不带路径信息)。这个成员可以是NULL。
    	open.nMaxFileTitle = 0;  //指定lpstrFileTitle缓冲的大小,以TCHARs为单位
    	open.lpstrInitialDir = NULL;  //指向以空字符结束的字符串,可以在这个字符串中指定初始目录。
    	open.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;//位标记的设置,你可以使用来初始化对话框
    	if (GetOpenFileName(&open))  // 显示打开选择文件对话框。  
    	{
    		path = file;
    		cout<<path + "
    ";
    	}
    	return path;
    }
    

    字符计数器

    int function::characterCount(CommandInfo commandInfo)
    {
    	int charNum = 0;
    	ifstream ReadFile;
    	ReadFile.open(commandInfo.filePath, ios::in);
    	char str[256];
    	while (!ReadFile.eof() && ReadFile.getline(str, 256))
    	{
    		for (int i = 0; i < strlen(str); i++)
    		{
    			if (str[i] == ' ' || str[i] == '
    ' || str[i] == '	' || str[i] == '
    ')
    				continue;
    			else charNum++;
    		}
    	}
    
    	ReadFile.close();
    return charNum;
    
    }
    

    单词计数器

    int function::wordCount(CommandInfo commandInfo)
    {
    	int wordNum = 0;
    	int charNum=0;
    	ifstream ReadFile;
    	ReadFile.open(commandInfo.filePath, ios::in);
    	char str[256];
    	while (!ReadFile.eof() && ReadFile.getline(str, 256))
    	{
    		for (int i = 0; i < strlen(str); i++)
    		{
    			if ((str[i] >= 'a' && str[i] <= 'z' )||(str[i] >= 'A' && str[i] <= 'Z'))   
    			{
    				charNum++;
    				continue;
    			}
    			else if(charNum>=2)  //字符数大于2即为单词
    			{
    				charNum = 0;
    				wordNum++;
    			}
    		}
    	}
    	if(charNum>=2) //避免末尾的单词没遇到其他字符导致数量丢失
    	{
    		wordNum++;
    	}
    	ReadFile.close();
    	return wordNum;
    }
    

    行数计数器

    int function::lineCount(CommandInfo commandInfo)
    {
    	ifstream ReadFile;
    	int lineNum = 0;
    	char line[256];
    	ReadFile.open(commandInfo.filePath, ios::in);
    	while (!ReadFile.eof()&& ReadFile.getline(line, 256, '
    '))
    	{
    		lineNum++;
    	}
    	ReadFile.close();
    	return lineNum;
    
    }
    

    扩展功能:代码行 / 空行 / 注释行等计数器

    DLC function::dlcCount(CommandInfo commandInfo)
    {
    	DLC dlc;
    	int lineNum = 0;
    	int charNum = 0;
    	ifstream ReadFile;
    	bool isNoteLine=false;
    	ReadFile.open(commandInfo.filePath, ios::in);
    	char str[256];
    	while (!ReadFile.eof() && ReadFile.getline(str, 256,'
    '))
    	{
    		charNum = 0;
    		for (int i = 0; i < strlen(str); i++)
    		{
    			if (isNoteLine)//"/**/"跨行注释
    			{
    				if (str[i] == '*' && (i + 1) < strlen(str))
    				{
    					if (str[i + 1] == '/')
    					{
    						dlc.noteLine++;
    						isNoteLine = false;
    						break;
    					}
    				}
    			}
    			else
    			{
    				if (charNum >= 2)
    				{
    					dlc.codeLine++;
    					break;
    				}
    			}
    
    			if (str[i] == '/'&& (i + 1) < strlen(str))
    			{
    				if (str[i + 1] == '/')	//单行注释
    				{
    					dlc.noteLine++;
    					break;
    				}
    				if (str[i + 1] == '*')
    				{
    					isNoteLine = true;
    					break;
    				}
    			}
    			if (str[i] != '	' && str[i] != '
    ' )  //字符数累计
    			{
    				charNum++;
    				continue;
    			}
    		}
    		if (isNoteLine)//多行注释跨行增加
    		{
    			dlc.noteLine++;
    		}
    		lineNum++;
    	}
    	if (charNum >= 2&&!isNoteLine)	//避免末尾的单词数量丢失
    	{
    		dlc.codeLine++;
    	}
    	dlc.nullLine = lineNum - dlc.codeLine - dlc.noteLine;
    	ReadFile.close();
    	return dlc;
    }
    

    6.测试代码

    1.单元测试

    ​ 对字符,单词,行数等等计数器进行测试
    在这里插入图片描述

    2.回归测试

    (1)空文件
    在这里插入图片描述

    在这里插入图片描述

    (2)单字符文件

    在这里插入图片描述

    在这里插入图片描述
    (3)单个单词测试

    在这里插入图片描述
    在这里插入图片描述
    (4)单行测试

    在这里插入图片描述

    在这里插入图片描述

    (5)源程序测试

    在这里插入图片描述

    在这里插入图片描述

    3. 运行测试

    (1)-c

    在这里插入图片描述

    (2)-w

    在这里插入图片描述

    (3)-l

    在这里插入图片描述
    (4)-a

    在这里插入图片描述

    (5)-x

    在这里插入图片描述
    在这里插入图片描述

    7.总结

    ​ 在这次个人项目中,不仅学到了平时没有使用的windowsAPI和不熟悉的部分区域代码,还学到了规划项目的重要性,测试的重要性及如何操作,受益匪浅,还踩了不少坑,挺棒的。
    ​ 其实这个项目还可以再进行以下完善:

    1. 实现更多要求的功能:

      • 用QT采用C++/用Unity采用C# 实现图形化界面
      • 增加可递归处理选中文件的目录下的子文件
      • 增加通配符(模糊处理)
    2. 增强可扩展性:将功能类封装成可修改,可自定义

    3. 提高效率:比如采用引用,改善算法

    4. 增强安全性:添加异常检测

    5. 提高封装程度:利用类的成员函数的公有和私有

    (C++可做的事蛮多的),但由于其他作业偷懒没做了。

    参考资料:

    1. C/C++中main函数接受外部参数的写法,以及如何传参数:https://blog.csdn.net/selina8921/article/details/79141031
    2. CString:https://baike.sogou.com/v817436.htm?fromTitle=CString
    3. OPENFILENAME:https://baike.baidu.com/item/OPENFILENAME/1166193?fr=aladdin
    4. C++读取txt数据出错(乱码、数据出错、文件打不开):https://blog.csdn.net/xiongly123/article/details/80057093
  • 相关阅读:
    统一回复《怎么学JavaScript?》
    nodejs配置简单HTTP服务器
    web跨域解决方案
    JavaScript 调试小技巧
    我从编程总结的 22 个经验
    Sublime Text 3103 Crack 破解 注册码(亲测有效)
    mstsc 远程序桌面登录的 c#开发
    突然顿悟的Javascript中的this
    解决Electron加载带jquery的项目报错问题
    ES6+ 开发 React 组件
  • 原文地址:https://www.cnblogs.com/AMzz/p/12500738.html
Copyright © 2020-2023  润新知