github地址 :
个人项目:WC
1.项目要求
wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。
实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:- 程序处理用户需求的模式为:
- wc.exe [parameter]
- 基本功能列表:
- wc.exe -c file.c //返回文件 file.c 的字符数
- wc.exe -w file.c //返回文件 file.c 的词的数目
- wc.exe -l file.c //返回文件 file.c 的行数
- 扩展功能:
- -s 递归处理目录下符合条件的文件。 --a 返回更复杂的数据(代码行 / 空行 / 注释行)。
- 空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
- 代码行:本行包括多于一个字符的代码。
- 注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
- } //注释
- 在这种情况下,这一行属于注释行。
- -s 递归处理目录下符合条件的文件。 --a 返回更复杂的数据(代码行 / 空行 / 注释行)。
- 高级功能:
- -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
- 需求举例: - wc.exe -s -a .c - 返回当前目录及子目录中所有.c 文件的代码行数、空行数、注释行数。
2.遇到的困难及解决方法
主要困难有
- 当双引号出现在注释之中时
- 当注释符出现在双引号或者是单引号之中时
- 当块注释符号出现在行注释符之后时
- 当块注释结束之后进入代码行,但是行末再次出现行注释时
- 某一行既可以是代码行,也可以是注释行,或者既可以是注释行,也可以是空行
一开始并没有考虑到第五点,然后就写出了一次程序,但是在后来听闻同学找了老师问清楚要求之后,整份代码都进行了重新书写,并且判断注释行,代码行,空行比较麻烦,最终使用了几个bool类型标记终于完成这一功能
当我完成上面所述的问题之后,我觉得我的代码实现能力涨了一大截,并且思考是否还有更为极端得情况。
3.关键代码or设计说明
本文实现了基本功能,和扩展功能
先进行文件内容的读取bool input(FILE * fp)//读入文本 { str = ""; char s; while((s = fgetc(fp)) != EOF) str = str + s; str = str + '\n'; if(str.length() == 1) { Null = true; } return Null; }
基本功能:直接调用相对应的函数完成
void Line()//统计行数{ int num = 0; for(int i = 0; i < str.length(); i ++) { if(str[i] == '\n') num ++; } if(!Null) printf("行数 :%d\n", num);}void Char()//统计字符{ int num = 0; for(int i = 0; i < str.length(); i ++) { if(str[i] != ' ' && str[i] != '\n' && str[i] != '\t') num ++; } if(!Null) printf("字符个数 :%d\n", num);}void Words()//统计单词{ int num = 0; bool flag = 0; for(int i = 0; i < str.length(); i ++) { if(str[i] <= 'z' && str[i] >= 'a' || str[i] <= 'Z' && str[i] >= 'A' || str[i] == '_') { if(!flag) num ++; flag = true; } else flag = false; } if(!Null) printf("单词个数 :%d\n", num);}
调用calc直接对读入的文件进行统计代码行,注释行,空行
void Calc(){bool line_comment = false; //行注释bool block_comment = false; //块注释标记bool comment_exist = false; //注释出现过标记string s_comment = "";string s_code = "";//注释里面的字符串和代码里面的字符串if(str[0] == '\n') Empty ++;else if(str[0] != ' ' && str[0] != '\t') s_code = s_code + str[0];for(int i = 1; i < str.length(); i ++){ if(str[i] == ' ' || str[i] == '\t') continue ; if(str[i] == '\n') { if(comment_exist || line_comment || block_comment) Comment ++; //注释判断 if(s_comment.length() == 0) { if(s_code.length() == 0) Empty ++; if(s_code.length() == 1 && (s_code[0] == '{' || s_code[0] == '}' || s_code[0] == ';')) Empty ++; } //空行判断 if(s_code.length() > 1 || (s_code[0] != '{' && s_code[0] != '}' && s_code[0] != ';')) Code ++; //代码行判断 s_code = ""; s_comment = ""; line_comment = false; comment_exist = false; //换行之后初始化 } else if(line_comment) //行注释中 { s_comment = s_comment + str[i]; comment_exist = true; } else if(block_comment) //块注释中 { s_comment = s_comment + str[i]; comment_exist = true; if(str[i - 1] == '*' && str[i] == '/') block_comment = false; //块注释终止 } else if(str[i - 1] == '/' && str[i] == '/') //将代码字符串最后一个 / 保存到注释字符串之中,并行注释标记为真 { s_code = s_code.substr(0, s_code.length() - 1); s_comment = s_comment + str[i - 1] + str[i]; line_comment = true; comment_exist = true; } else if(str[i - 1] == '/' && str[i] == '*') //将代码字符串最后一个 / 保存到注释字符串之中,并块注释标记为真 { s_code = s_code.substr(0, s_code.length() - 1); s_comment = s_comment + str[i - 1] + str[i]; block_comment = true; comment_exist = true; } else if(str[i] == '\"') //读到双引号时,直接循环到下一个双引号, 并保存至代码字符串之中 { s_code = s_code + str[i]; while(str[++ i] != '\"') { s_code = s_code + str[i]; } s_code = s_code + str[i]; } else if(str[i] == '\'') //读到单引号时,直接循环到下一个单引号, 并保存至代码字符串之中 { s_code = s_code + str[i]; while(str[++ i] != '\'') { s_code = s_code + str[i]; } s_code = s_code + str[i]; } else //普通字符 s_code = s_code + str[i];}if(!Null){ printf("注释行数 : %d\n", Comment); printf("代码行数 : %d\n", Code); printf("空行数 : %d\n", Empty);}
4.测试报告
由于技术有限,笔者采取的是手工测试
第一组测试结果如下:
第二组测试结果如下:
第三组测试结果如下:
第四组测试结果如下:
5.PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 40 |
· Estimate | · 估计这个任务需要多少时间 | 15 | 40 |
Development | 开发 | 540 | 915 |
· Analysis | · 需求分析 (包括学习新技术) | 180 | 300 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 15 | 15 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 0 | 0 |
· Design | · 具体设计 | 15 | 60 |
· Coding | · 具体编码 | 150 | 180 |
· Code Review | · 代码复审 | 30 | 90 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | 160 | 230 |
· Test Report | · 测试报告 | 120 | 180 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 715 | 1185 |
5. 记录自己的学习进度条(每周追加)
第N周 | 新增代码行 | 累计代码 | 本周学习耗时 | 累计学习耗时 |
---|---|---|---|---|
1 | 100 | 100 | 8 | 8 |
2 | 215 | 215 | 11.5 | 19.5 |