第2周个人作业:WordCount
-
Github项目链接:
https://github.com/JarrySmith/WC
-
PSP表格:
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
10 |
5 |
· Estimate |
· 估计这个任务需要多少时间 |
10 |
5 |
Development |
开发 |
825 |
1100 |
· Analysis |
· 需求分析 (包括学习新技术) |
200 |
300 |
· Design Spec |
· 生成设计文档 |
30 |
60 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
20 |
30 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
15 |
20 |
· Design |
· 具体设计 |
30 |
30 |
· Coding |
· 具体编码 |
400 |
450 |
· Code Review |
· 代码复审 |
30 |
60 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
100 |
150 |
Reporting |
报告 |
60 |
70 |
· Test Report |
· 测试报告 |
30 |
40 |
· Size Measurement |
· 计算工作量 |
10 |
10 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
20 |
20 |
|
合计 |
890 |
1175 |
-
解题思路
首先很明显,分为包含-s的目录寻找以及非目录寻找的其他命令,我采取的是遍历命令行参数,获取需要进行的操作,如计算单词,计算行数等等.然后有些选项如-o,-e则在第一遍遍历的时候进行检测,其后面是不是有指定文本,如果指定了,那么把输出指向该文本,如果没有指定,那么就直接报错,不需要执行接下来的命令,加快了速度.
说到文本,那就有关于文本读写方面的内容,我参考了博客【1】中的文本操作。递归遍历参考了博客【2】,获取当前路径参考了博客【3】
再统计字符,单词,行数比较简单,不多说.值得注意的是-s和-a。-s需要指定特定目录下的指定类型的文本,这里牵涉到关于文本类型的过滤,是默认当前目录还是命令行传入的目录.*.type可以单独存在也可接在目录后面,这都是需要在遍历的时候去解析的。至于-a,自然是关于注释行,空行,代码行的判断了,我的实现是,先判断是不是空行,再判断是不是注释行,如果都不是,那就是代码行.其中有一种是多行注释的最后加上了代码,算是代码行,关于这个,在多行结束判断中,加入一个判断最后一个字符是否为'/'。
对于每个选项的细节实现上不做过多的展开.稍后的代码展现可以再看到具体的.
-
程序设计实现过程
由于工程量不大,所以把所有函数写在一个类里静态调用.共十一个函数.
countchars、countlines、count_word分别统计字符数,行数,单词数
is_emptyline、is_expline 用来判断是否为空行,注释行,是被countdetail调用
get_stopword、readToString、saveresult都是辅助函数,功能为获取停用词表的词,将读入的文本转化为字符串,保存统计结果
WC、traversepath为两个关键的入口函数,根据是否包含-s分为两个部分去进行统计工作
-
代码说明
1.WC函数,关键入口函数,解析命令行参数表.在第一遍遍历进行了错误判断,利用param是否包含-s进行分支选择,分别处理
public static void WC(String[] args) { int words = 0; int lines = 0; int chars = 0; int[] detail = new int[3]; CharSequence save = ".txt"; String filepath = null; boolean checked_file = false; for (int i = 0; i < args.length; i++) { if (args[i].contains(".txt")) continue; //停用词的文件判断 if (args[i].equals("-e")) { if (i == args.length - 1) { System.out.println("没有指定停用词文本"); err = true; } else if (!(args[i + 1].contains(save))) System.out.println("停用词文本需紧跟在-e后"); else stop_path = args[i + 1]; } //判断是否函数输出文本 if (args[i].equals("-o")) { if (i == args.length - 1) { System.out.println("没有指定输出结果文本"); err = true; } else if (!(args[i + 1].contains(save))) System.out.println("result.txt需紧跟在-o后"); else save_path = args[i + 1]; } string_args.append(args[i]); } param = string_args.toString(); if (!err) { if (param.contains("-s")) { //默认path为当前目录 String path = System.getProperty("user.dir"); for (int i = args.length - 1; i > 0; i--) { if (args[i].contains("*.")) { //获取指定文件类型和指定目录 if(args[i].length()>15) path= args[i].split("\\.")[0].replace("*",""); filetype = "." + args[i].split("\\.")[1]; } } //开始遍历目录 traversepath(path); } else { //错误判断 for (int i = 0; i < args.length; i++) { if (args[i].contains("*.")){err=true;System.out.println("只有输入-s才能进行全目录遍历规定文件");} if (args[i].contains(".")) { filepath = args[i]; break; } } if(!err) { //及非遍历统计 if (param.contains("-c")) chars = countchars(filepath); if (param.contains("-l")) lines = countlines(filepath); if (param.contains("-w")) words = count_word(filepath); try { if (param.contains("-a")) detail = countdetail(filepath); } catch (IOException e) { e.printStackTrace(); } } } } saveresult(words,lines,chars,detail,filepath); }
2.traversepath函数 根据特定的文本类型,遍历指定目录及其子目录,分别进行统计工作然后保存
public static void traversepath(String path) { File file = new File(path); if (file.exists()) { File[] files = file.listFiles(); //如果是个空文件夹 if (files.length == 0) { return; } else { for (File file2 : files) { if (file2.isDirectory()) { //遍历子目录 traversepath(file2.getAbsolutePath()); } else { String filename = file2.getName(); if (filename.endsWith(filetype)) { String filepath = path + '\\' + filename; int words = 0; int lines = 0; int chars = 0; int[] detail = new int[3]; //根据参数进行统计 try { if (null == param) break; if (param.contains("-a")) detail = countdetail(filepath); if (param.contains("-w")) words = count_word(filepath); if (param.contains("-c")) chars = countchars(filepath); if (param.contains("-l")) lines = countlines(filepath); saveresult(words, lines, chars, detail, filename); } catch (IOException e) { e.printStackTrace(); } } } } } } }
测试设计过程
如何设计?覆盖所有判断路径,分支
关于命令行参数不完整和不正确 会导致程序高风险
测试用例设计如下:
- wc.exe -l a.c
- wc.exe -w a.c
- wc.exe -c a.c
- wc.exe -a a.c
- wc.exe -l a.c -o result.txt
- wc.exe -l a.c -o
- wc.exe -w a.c -e stoplist.txt
- wc.exe -w a.c -e
- wc.exe -s -a *.c
- wc.exe -s -a
- wc.exe -s -a *.java
测试脚本代码如下:
wc.exe -l a.c
wc.exe -w a.c
wc.exe -c a.c
wc.exe -a a.c
wc.exe -l a.c -o result.txt
wc.exe -l a.c -o
wc.exe -w a.c -e stoplist.txt
wc.exe -w a.c -e
wc.exe -s -a *.c
wc.exe -s -a
wc.exe -s -a *.java
pause>nul
参考文献链接
【1】https://www.cnblogs.com/oracleblogs/p/6591656.html
【2】https://www.cnblogs.com/azhqiang/p/4596793.html
【3】https://www.cnblogs.com/franson-2016/p/5728280.html