【结对项目】项目记录:单词计数 WordCount

结对项目:单词计数


一、项目要求

1.    实现统计文件的字符数、单词数、行数。

2.    实现递归处理目录下符合条件的文件,返回更加复杂的数据。

3.    实现图形界面功能。


二、github链接

        链接:https://github.com/LLFKirito/WordCount-BIT1120161918


三、结对同学

        结对同学:马伯乐(1120161922)


四、项目计划PSP表格

计划安排表

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


五、设计实现

总体设计

       程序流程图如下


       程序分为main、define、fundamentalextendedInterface五个文件,分别实现对外接口,基本输入输出操作、基础功能、扩展功能、高级功能。

函数关系图


代码规范

       参考教材上的注释示例:

        /// <summary>  </summary> 
        /// <param name="?">  </param> 
        /// <return>  </return> 

       根据种方案写注释。

       函数命名采用下划线命名法。


六、解题思路与代码说明

        首先对主函数传来的参数进行探测,本项目对错误的检查能力很强,对不同的输入错误有不同的返回报错信息。

        check_file_name用于检查文件是否存在并可以读取,返回-1边表示文件不存在,返回-2表示文件存在但没有读取权限,返回1表示文件有访问权限 。

int check_file_name(char filename[])
{
	if (access(filename, 0) != 0) { return -1; }	// 文件不存在返回-1 
	if (access(filename, 4) != 0) { return -2; }	// 文件不能读取返回-2 
	return 1;
}

        对命令的检查也很严格,有任何错误就能输出错误信息。

int check_order(char order[])
{
	int len = strlen(order);
	if (len != 2 || order[0] != '-') return -1;
	if (order[1] == 'c' || order[1] == 'w' || order[1] == 'l' || order[1] == 'a') {
		return 1;
	}
	else return -1;
}

        为了处理有些文件名有空格,在参数上文件名会占用多个参数,特别处理。

int num_para;
for (num_para = argc - 1; num_para > 1; num_para--) {
    if (   strcmp(argv[num_para], "-s") == 0 || strcmp(argv[num_para], "-x") == 0
	|| strcmp(argv[num_para], "-c") == 0 || strcmp(argv[num_para], "-w") == 0
	|| strcmp(argv[num_para], "-l") == 0 || strcmp(argv[num_para], "-a") == 0 )
	{break;}
}
char  filename[500] = {0};
strcat(filename, argv[num_para+1]);
for (int i = num_para+2;i < argc;i++) {
    strcat(filename, " ");
    strcat(filename, argv[i]);
}

        基本功能处理比较简单:

        统计字数:读到正确字符就+1。

int count_character(char file[])
{
	int ch_num = 0;
	char ch;
	freopen(file, "r", stdin);
	while ((ch = getchar()) != EOF) {
		if (ch != ' '&&ch != '\n'&&ch != '\t')
			ch_num++;
	}
	fclose(stdin);
	return ch_num;
}

        统计单词:逐个读取,字母被分隔就+1.

int count_word(char file[])
{
	int w_num = 0, is_word = 0;
	char ch;
	freopen(file, "r", stdin);
	while ((ch = getchar()) != EOF) {
		if ((ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z') || ch == '_')
			is_word = 1;
		else {
			if (is_word) {
				w_num++;
				is_word = 0;
			}
		}
	}
	fclose(stdin);
	return w_num;
}

        统计行数:直接读取'\n'。

int count_line(char file[])
{
	int l_num = 0;
	char ch;
	freopen(file, "r", stdin);
	while ((ch = getchar()) != EOF) {
		if (ch == '\n')
			l_num++;
	}
	fclose(stdin);
	return l_num;
}

        递归处理部分,每次搜索当前文件的匹配文件和找到子文件并依次进入。

void search_file(string path, int idx)
{
	struct _finddata_t filefind;
	string cur = path + "*.*";
	int done = 0, handle;
	if ((handle = _findfirst(cur.c_str(), &filefind)) != -1) {
		while (!(done = _findnext(handle, &filefind))) {
			if (strcmp(filefind.name, "..") == 0)
				continue;
			if ((_A_SUBDIR == filefind.attrib)) {  //目录
				cur = path + filefind.name + '\\';
				search_file(cur, idx);    //递归处理
			}
			else {
				int len = strlen(filefind.name);
				for (int i = 0; i < len; i++) {
					if (filefind.name[i] == '.') {
						len = i;
						break;
					}
				}
				if (strcmp(filefind.name + len, para[idx] + 1) == 0) {
					cur = path + filefind.name;
					printf("%s:\n", filefind.name);
					for (int i = 1; i < idx; i++)
						basic_command(para[i], &cur[0]);
				}
			}
		}
		_findclose(handle);
	}
}

        高级功能通过调用界面程序来执行。

ShellExecuteA(NULL, "open", "WordCount.exe", NULL, NULL, SW_SHOW);

        界面部分利用C#搭建,界面实际效果图如下(背景是本人相当喜欢的Sword Art Online):


        点击浏览会弹出资源管理器,在此选择文件,点统计输出统计信息。


        统计功能直接调用拓展功能的函数,文件资源管理器调用如下:

private void view_Click(object sender, EventArgs e)
{
    OpenFileDialog openFileDialog1 = new OpenFileDialog();   //显示选择文件对话框 
    openFileDialog1.InitialDirectory = "c:\\";
    openFileDialog1.Filter = "All files (*.*)|*.*";
    openFileDialog1.FilterIndex = 2;
    openFileDialog1.RestoreDirectory = true;
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        this.txtFilepath.Text = openFileDialog1.FileName;     //显示文件路径 
    }
}

        调用函数通过直接启动wc.exe实现:

private void count_Click(object sender, EventArgs e)
{
    if (string.IsNullOrEmpty(this.txtFilepath.Text.Trim()))
    {
        MessageBox.Show("请选择文件");
    }
    string[] arg = new string[10];
    arg[0] = "-c"; arg[1] = "-w"; arg[2] = "-l"; arg[3] = "-a";
    arg[4] = this.txtFilepath.Text.Trim();
    StartProcess(@"wc.exe", arg);
}


七、测试与分析

单元测试

       一共设计了11个单元测试:

#include "stdafx.h"
#include "CppUnitTest.h"
#include "..\wc\define.h"
#include "..\wc\define.cpp"
#include "..\wc\fundamental.h"
#include "..\wc\fundamental.cpp"
#include "..\wc\extended.h"
#include "..\wc\extended.cpp"


using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest1
{		
	TEST_CLASS(UnitTest1)
	{
	public:
		
		TEST_METHOD(TestMethod1)
		{
			int examine_1 = check_file_name("..\\UnitTest1\\TestCase\\test3.c");
			int examine_2 = check_file_name("..\\UnitTest1\\TestCase\\test4.cpp");
			int examine_3 = check_file_name("..\\UnitTest1\\TestCase\\test8.py");
			int examine_4 = check_file_name("..\\UnitTest1\\TestCase\\1120161918.txt");
			int examine_5 = check_file_name("..\\UnitTest1\\TestCase\\1120161922.cpp");
			
			Assert::AreEqual(examine_1 == 1, true);
			Assert::AreEqual(examine_2 == 1, true);
			Assert::AreEqual(examine_3 == 1, true);
			Assert::AreEqual(examine_4 == -1, true);
			Assert::AreEqual(examine_5 == -1, true);
		}
		
		TEST_METHOD(TestMethod2)
		{
			int examine_1 = check_order("-c");
			int examine_2 = check_order("-w");
			int examine_3 = check_order("-l");
			int examine_4 = check_order("-a");
			int examine_5 = check_order("-cxxcsc");
			int examine_6 = check_order("c");
			
			Assert::AreEqual(examine_1 == 1, true);
			Assert::AreEqual(examine_2 == 1, true);
			Assert::AreEqual(examine_3 == 1, true);
			Assert::AreEqual(examine_4 == 1, true);
			Assert::AreEqual(examine_5 == -1, true);
			Assert::AreEqual(examine_6 == -1, true);
		}
		
		TEST_METHOD(TestMethod3)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test1.c";
			int num_ch = count_character(file);
			
			Assert::AreEqual(num_ch == 36, true);
		}
		
		TEST_METHOD(TestMethod4)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test1.c";
			int num_w = count_word(file);
			
			Assert::AreEqual(num_w == 6, true);
		}
		
		TEST_METHOD(TestMethod5)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test1.c";
			int num_l = count_line(file);
			
			Assert::AreEqual(num_l == 5, true);
		}
		
		TEST_METHOD(TestMethod6)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test2.c";
			int num_ch = count_character(file);
			int num_w = count_word(file);
			int num_l = count_line(file);
			
			Assert::AreEqual(num_ch == 44, true);
			Assert::AreEqual(num_w == 7, true);
			Assert::AreEqual(num_l == 5, true);
		}
		
		TEST_METHOD(TestMethod7)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test3.c";
			int num_bl = count_blankline(file);
			int num_nl = count_noteline(file);
			int num_cl = count_codeline(file);
			
			Assert::AreEqual(num_bl == 2, true);
			Assert::AreEqual(num_nl == 0, true);
			Assert::AreEqual(num_cl == 3, true);
		}
		
		TEST_METHOD(TestMethod8)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test4.cpp";
			int num_ch = count_character(file);
			int num_w = count_word(file);
			int num_l = count_line(file);
			int num_bl = count_blankline(file);
			int num_nl = count_noteline(file);
			int num_cl = count_codeline(file);
			
			Assert::AreEqual(num_ch == 224, true);
			Assert::AreEqual(num_w == 52, true);
			Assert::AreEqual(num_l == 15, true);
			Assert::AreEqual(num_bl == 2, true);
			Assert::AreEqual(num_nl == 0, true);
			Assert::AreEqual(num_cl == 13, true);
		}
		
		TEST_METHOD(TestMethod9)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test5.cpp";
			int num_ch = count_character(file);
			int num_w = count_word(file);
			int num_l = count_line(file);
			int num_bl = count_blankline(file);
			int num_nl = count_noteline(file);
			int num_cl = count_codeline(file);
			
			Assert::AreEqual(num_ch == 338, true);
			Assert::AreEqual(num_w == 81, true);
			Assert::AreEqual(num_l == 37, true);
			Assert::AreEqual(num_bl == 15, true);
			Assert::AreEqual(num_nl == 0, true);
			Assert::AreEqual(num_cl == 22, true);
		}
		
		TEST_METHOD(TestMethod10)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test6.cpp";
			int num_ch = count_character(file);
			int num_w = count_word(file);
			int num_l = count_line(file);
			int num_bl = count_blankline(file);
			int num_nl = count_noteline(file);
			int num_cl = count_codeline(file);
			
			Assert::AreEqual(num_ch == 210, true);
			Assert::AreEqual(num_w == 47, true);
			Assert::AreEqual(num_l == 21, true);
			Assert::AreEqual(num_bl == 7, true);
			Assert::AreEqual(num_nl == 0, true);
			Assert::AreEqual(num_cl == 14, true);
		}
		
		TEST_METHOD(TestMethod11)
		{
			char file[] = "..\\UnitTest1\\TestCase\\test9.py";
			int num_ch = count_character(file);
			int num_w = count_word(file);
			int num_l = count_line(file);
			int num_bl = count_blankline(file);
			int num_nl = count_noteline(file);
			int num_cl = count_codeline(file);
			
			Assert::AreEqual(num_ch == 202, true);
			Assert::AreEqual(num_w == 25, true);
			Assert::AreEqual(num_l == 19, true);
			Assert::AreEqual(num_bl == 2, true);
			Assert::AreEqual(num_nl == 0, true);
			Assert::AreEqual(num_cl == 17, true);
		}
		
	};
}

       测试文件夹:

       测试结果:


       代码覆盖率如下:


八、PSP表格总结

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


九、总结与反思

       这一次是做结对项目,俩人合作完成单词计数。难点主要在需求分析上,因为项目需求写的不是特别明白,很多细节需要反复讨论以及再次咨询老师才能够完全确定。

       这一次需求对界面要求特别高,尤其是需要像调用文件资源管理器一样来处理单个文件。难度其实挺大的。

       代码编写是两个人编写,所以需要先约定代码风格,比如采用下划线命名法,分文件写的时候,先规划每个函数实现功能,精确到参数个数及类型,返回值类型,然后分开写的时候就算不知道对方写的部分也能调用函数。结对项目与个人项目不同,它更加考察我们对项目的分工与合作,如何把一个大的项目拆分成多个小项目,如何多人合作,程序连接时如何能正确执行,各个模块间接口如何,这些是本次项目所带给我们最多值得学习的地方。

       简而言之,结对项目的完成提升了我们对完成大型项目的能力,规划,分工,合作,这些都是很重要的经验。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值