Github项目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 40 | 35 |
· Estimate | · 估计这个任务需要多少时间 | 90 | 120 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 100 | 140 |
· Design Spec | · 生成设计文档 | 120 | 90 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 50 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 25 |
· Design | · 具体设计 | 20 | 55 |
· Coding | · 具体编码 | 300 | 450 |
· Code Review | · 代码复审 | 40 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 100 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 120 | 150 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 | 10 |
合计 | 1040 | 1295 |
解题思路
项目工作被分成三个层次:基本、扩展、高级。
应该由最底层的单文件处理出发,延伸到多文件的处理。
由各项的功能如何定义和实现出发,来充实我们的程序。
- -c 统计文件中的字符数
以程序的眼光看待,任何字符(除了‘\r’),均算是一个字符。
基于这样的定义,对目标文件的每读入一个字符,若其不是‘\r’,均增加统计的字符数。 - -w 统计文件中的词的数量
词的定义多种多样,这里的定义采用一系列连续的字母或数字或下划线,为一个词;或者对于中文来说,一个字即为一个词。
基于这样的定义,我们可以把所有键盘上打出的符号视作一个栏杆,栏杆两边的有字符数部分视作是两个独立的词,以此来统计词的数量。 - -l 统计文件*有几行
行数的判定十分明朗,当程序每读到一个‘\n’时,或文件读完毕时(但是文件有内容时),视作一个换行,如此来统计行数。 - -s 递归处理目录下符合条件的文件
C++的文件处理十分麻烦,我在此处卡了许久。需要利用封装度较低的库函数来实现对文件夹的便利和通配符的支持,还有中文的支持。由此使用了io.h、direct.h、windows.h、getopt,这四个库文件。通过自己手写封装函数来实现自己的需求。 - 返回更复杂的数据(代码行 / 空行 / 注释行)。
相较于上一个而言,这个较为简单和明确:
- 空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
- 代码行:本行包括多于一个字符的代码。
- 注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
} //注释
在这种情况下,这一行属于注释行。
设计实现过程
程序设计主要分三个部分,主要逻辑围绕着main展开。
程序包含两个类,其中一个负责全流程的读入解析和输出,另外一个工具类作为中文支持存在,提供字符转换。
工具类 WStringTool中包含有
- string GbkToUtf8(const std::string& strGbk);
- string Utf8ToGbk(const std::string& strUtf8);
- wstring UTF8ToUnicode(const char* str);
- char *UnicodeToUTF8(const wchar_t* str);
- wstring GbkToUnicode(const char* strGbk);
- string UnicodeToGbk (const std::wstring& strUnicode);
六种方法,这里只使用了GbkToUnicode和UTF8ToUnicode这两个方法。
在main()中使用库文件getopt来获取命令行下每一个参数存在性。
while(true)
{
int c = getopt(argc, argv, par);
if(c == -1)
break;
switch (c) {
case 'c':Work::calcChar = true;
break;
case 'w':Work::calcWord = true;
break;
case 'l':Work::calcLine = true;
break;
case 's':recursive = true;
break;
case 'a':Work::detail = true;
break;
case 1: //读入到文件参数
match.push_back(optarg);
default:
break;
}
}
这里的case 1会对每一个文件都进行压入,可以通过此点来拓展出进行处理多文件的能力。
work.cpp中读入文件的操作,权衡了易用性和高效性。
bool Work::readFile(const wchar_t* fileName)
{
ifstream fin;
fin.open(fileName, ios::binary);
if(fin.is_open() == false)
return false;
fin.seekg(0, ios::end);
int len = static_cast<int>(fin.tellg()) + 1;
fin.seekg(0, ios::beg);
delete res;
init();
res = new char[len];
fin.read(res, len);
res[len-1] = '\0'; // before is 0xCD
this->fileName = wstring(fileName);
return true;
}
关于每一行代码的检测函数,集成度较高,解耦难度高,请到我项目地址去查看。
测试运行
运行参数:wc.exe helloworld.txt -c -w -l
运行结果:
...\helloworld.txt
The number of char is 104
The number of word is 15
The number of line is 8
运行参数:wc.exe *.txt -c -w -l
运行结果:
...\helloworld.txt
The number of char is 104
The number of word is 15
The number of line is 8
...\x.txt
The number of char is 5
The number of word is 2
The number of line is 1
运行参数:wc.exe *.txt -s -a
运行结果:
...\helloworld.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 1
...\x.txt
The number of blank-line is 0
The number of code-line is 1
The number of annotation-line is 0
...\kkkk\ssss.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 0
...\kkkk\x.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 0
...\ssss\ssss.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 0
...\ssss\x.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 0
...\kkkk\ssss\ssss.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 0
...\kkkk\ssss\x.txt
The number of blank-line is 0
The number of code-line is 7
The number of annotation-line is 0
程序运行的截图:
之前提及到的处理多文件的能力的拓展
项目小结
这是我个人第一次在编程中使用软件工程的思想,在实践过程中,我发现理论和实践的结合需要多次操作,才能更好的融会贯通,使得理论指导实践,成就一项良好的工程。
项目开始时选定的C++,低估了其掌握的难度,尤其是在文件的遍历和文件编码中踩坑甚多,让我看到了我在语言掌握上的不足,期待今后更加努力。
软件工程的PSP表,第一次使用,对于自己每项任务完成时间的估计没有经验参考,随着直觉估量,导致偏差过大,工程完成预期时间严重拖后,需要进行进一步的学习。