wordCount
1. 项目相关要求
这个项目要求写一个命令行程序 ,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。 作为实战项目,我完成的要求如下:
- 基本功能
-c
统计字符数(支持√)-w
统计单词数(支持√)-l
统计行数(支持√)
- 扩展功能
-s
递归处理目录下符合条件的文件(支持√)-a
返回更复杂的数据——代码行 / 空行 / 注释行(支持√)- 支持各种文件的通配符(支持√)
- 高级功能
- 基本的Windows GUI 程序操作(支持√)
- 支持通过图形界面展现文件的信息(支持√)
2. 项目耗时预计(PSP)
实际耗时 PSP 表格在 blog 末尾给出
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | |
· Estimate | · 估计这个任务需要多少时间 | 30 | |
Development | 开发 | 550 | |
· Analysis | · 需求分析 (包括学习新技术) | 20 | |
· Design Spec | · 生成设计文档 | 50 | |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | |
· Design | · 具体设计 | 120 | |
· Coding | · 具体编码 | 240 | |
· Code Review | · 代码复审 | 30 | |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | |
Reporting | 报告 | 120 | |
· Test Report | · 测试报告 | 60 | |
· Size Measurement | · 计算工作量 | 30 | |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | |
合计 | 700 |
3. 解题思路
刚拿到题目时以为是一个简单的统计单词的程序,但是当认真阅读项目的要求后,发现基础功能实现比较简单,但是对于扩展功能有点不知道如何下手。主要原因是对于项目要求中给出的代码行、注释行的解释十分疑惑。
空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
代码行:本行包括多于一个字符的代码。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
? } //注释
在这种情况下,这一行属于注释行。
于是我决定先明确这些定义后再写代码,于是找了许多关于代码行和注释行的区别。最终发现最方便可以分辨这两者的工具是编辑器(或IDE),因为这些编辑器原生支持代码检查(当然记事本除外= =),可以区分出极端情况下究竟属于代码行还是注释行,譬如:
/** **/ int a = 3;
4. 设计实现过程
/view/MainView.java
负责显示 -x
参数打开的图形页面
/service/WordCount.java
负责处理命令行参数和代码计数
st=>start: 用户命令行输入
e=>end: 程序结束
cond=>condition: 是否含有 -x 参数
op_command=>operation: 命令行显示
op_view=>operation: 图形页面显示
st->cond
cond(yes)->op_view->e
cond(no)->op_command->e
5. 代码说明
以下是各参数实现的关键代码
- 基本功能的实现
// /view/WrodCount.java
public void solution(File f) throws Exception {
// 省略其他实现...
while ((st = br.readLine()) != null) {
text.append(st).append("\n");
// 基本功能
// 匹配字符数
totalCharacters += st.length();
// 匹配函数
totalLines++;
// 匹配单词
int words = 0;
Pattern pattern = Pattern.compile("\\w+");
Matcher matcher = pattern.matcher(st);
while (matcher.find()) {
words++;
}
totalWords += words;
}
// 省略其它实现...
}
- 扩展功能的实现
public void solution(File f) throws Exception {
// 省略...
while ((st = br.readLine()) != null) {
// 省略...
// 扩展功能
if (!f.getAbsolutePath().endsWith(".txt")) {
int indexOfFirstQuote = st.indexOf("\"");
int indexOfSecondQuote = st.indexOf("\"", indexOfFirstQuote + 1);
if (indexOfFirstQuote != -1 && indexOfSecondQuote != -1) {
st = st.substring(0, indexOfFirstQuote) + st.substring(indexOfSecondQuote + 1, st.length() - 1);
} else if (indexOfFirstQuote != -1 && indexOfSecondQuote == -1) {
st = st.substring(0, indexOfFirstQuote);
}
if (hasMultiLineComment) {
commentLine++;
int indexOfMultiLineCommentEnd = st.indexOf("*/");
if (indexOfMultiLineCommentEnd >= 0) {
// /*
// abc
// >*/
hasMultiLineComment = false;
}
} else {
if (st.trim().length() <= 1) { // 判断空行
blankLine++;
} else {
int indexOfDoubleSlash = st.indexOf("//");
int indexOfMultiLineCommentBegin = st.indexOf("/*");
if (indexOfDoubleSlash == -1 && indexOfMultiLineCommentBegin == -1) { // 不存在注释
codeLine++;
} else if (indexOfDoubleSlash != -1 && indexOfMultiLineCommentBegin == -1) { // 只存在单行注释
commentLine++;
} else if (indexOfDoubleSlash == -1 && indexOfMultiLineCommentBegin != -1) { // 只存在多行注释
commentLine++;
hasMultiLineComment = true;
if (st.indexOf("*/") > indexOfMultiLineCommentBegin) { // 多行注释结束于同一行
hasMultiLineComment = false;
}
} else if (indexOfDoubleSlash != -1 && indexOfMultiLineCommentBegin != -1) { // 存在单行注释和多行注释
if (indexOfDoubleSlash < indexOfMultiLineCommentBegin) { // 单行注释在前
commentLine++;
} else { // 多行注释在前
commentLine++;
hasMultiLineComment = true;
if (st.indexOf("*/") > indexOfMultiLineCommentBegin) { // 多行注释结束于同一行
hasMultiLineComment = false;
}
}
}
}
}
}
}
}
6. 测试运行
文件测试
- 测试空文本:
- 测试只有一个字符的文件:
- 测试只有一个单词的文件:
- 测试只有一行的文件:
- 测试标准源文件:
参数测试
-s
递归测试
- 通配符?*支持
匹配所有扩展格式为 .txt
的文件
匹配所有test_?.*
的所有文件
-x
显示图形化界面
覆盖性测试
7. 实际花费时间(PSP)
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 50 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 50 |
Development | 开发 | 550 | 940 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 20 |
· Design Spec | · 生成设计文档 | 50 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 50 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 10 |
· Design | · 具体设计 | 120 | 150 |
· Coding | · 具体编码 | 240 | 480 |
· Code Review | · 代码复审 | 30 | 10 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 50 |
Reporting | 报告 | 120 | 140 |
· Test Report | · 测试报告 | 60 | 50 |
· Size Measurement | · 计算工作量 | 30 | 50 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 700 | 1130 |
8. 项目小结
根据上面给出的 PSP 表可以很明显看出,我花在计划还有报告的时间基本和估计的时间差不多,但是开发的时间(约 940 minutes)却远远超出一开始的预计(550 minutes)。这里说明两点,一点是自己对实际开发持乐观的态度,因此导致对实际项目开发的时间估计较短;还有一点是开发的时间过长。
仔细看开发中具体哪一项花费的时间最多,我发现我花了几乎两倍的具体编码时间,现在回顾起来发现自己在浪费了大量时间在扩展功能的开发上,主要原因是在动手写代码前没有彻底明确需求(特别是对扩展部分注释行定义的理解),导致在写代码过程中删删改改,越写感觉越多bug,然后再推倒重来...因此教训就是前期要花更多的时间在需求分析上,从而避免在开发过程中频繁地改动已经写过的代码,降低整个开发效率。
原文地址:https://www.cnblogs.com/zkyyo/p/9637749.html