课程 | 软件工程1916|W(福州大学) |
---|---|
做业要求 | 结对第二次—文献摘要热词统计及进阶需求 |
结队博客 | 221600328 221600106 |
Github地址 | 基础需求 |
做业目标 | 实现一个可以对文本文件中的单词的词频进行统计的控制台程序。 |
具体分工 | 221600328:主要代码及工做 221600106:部分代码,编写文档 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 50 |
Estimate | 估计这个任务须要多少时间 | 1700 | 2050 |
Development | 开发 | 300 | 350 |
Analysis | 需求分析 (包括学习新技术) | 180 | 220 |
Design Spec | 生成设计文档 | 60 | 70 |
Design Review | 设计复审 | 60 | 80 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
Design | 具体设计 | 180 | 220 |
Coding | 具体编码 | 770 | 850 |
Code Review | 代码复审 | 120 | 100 |
Test | 测试(自我测试,修改代码,提交修改) | 80 | 70 |
Reporting | 报告 | 160 | 180 |
Test Repor | 测试报告 | 30 | 35 |
Size Measurement | 计算工做量 | 30 | 25 |
Postmortem & Process Improvement Plan | 过后总结, 并提出过程改进计划 | 120 | 55 |
合计 | 2180 | 2325 |
WordCount基本需求
实现一个命令行程序,不妨称之为wordCount。
第一步、实现基本功能
输入文件名以命令行参数传入。例如咱们在命令行窗口(cmd)中输入:
//C语言类
wordCount.exe input.txt
//Java语言
java wordCount input.txt
则会统计input.txt中的如下几个指标
1.统计文件的字符数:java
2.统计文件的单词总数,单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。c++
3.统计文件的有效行数:任何包含非空白字符的行,都须要统计。git
4.统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词。github
5.按照字典序输出到文件result.txt:例如,windows95,windows98和windows2000同时出现时,则先输出windows2000正则表达式
6.输出的格式为
characters: number
words: number
lines: number
...
此次题目主要是两个部分:字词计数和文件读写,原本想用c++来进行编码,后来发现使用Java更为简便,有许多类库函数能够直接调用来解决问题,因而就使用了Java。
思路主要是写一个Count类,类里包含各个小问题解决的方法,如CountCharacter,CountLine和CountWord。
使用BufferedReader读文件,读出来的数据用String存储,对该字符串进行修改,获取单词及行数,最后重写compare对单词进行排序。
有了总体思路后,对每一个方法逐个击破,便迎刃而解了。windows
一开始写这个代码十分不规范。。用的变量名简直为所欲为,后面按照Java规范修改了一下,总体还行。app
类图
(https://img2018.cnblogs.com/blog/1593605/201903/1593605-20190315170442501-135307741.png)ide
流程图
函数
传入文件名,统计非空行数,统计字符数,统计单词数,统计最多的10个单词及其词频
传入文件名
CountCharacter:计算字符数
CountWord:计算单词
CountLine:计算行数
统计单词及计算词频部分,使用split正则表达式分词,存入HashMap,重写compare,存入List进行排序。
public int CountWord() { int wordNum=0; String regex="[^A-Za-z0-9]"; String textLowerCase= text.toLowerCase(); String textcontents = textLowerCase.replaceAll(regex, " "); String[] textarrays = textcontents.split("\\s+"); for(int i=0; i<textarrays.length;i++) { if(textarrays[i].length()>=4) if(Character.isLetter(textarrays[i].charAt(0)) && Character.isLetter(textarrays[i].charAt(0)) && Character.isLetter(textarrays[i].charAt(0)) && Character.isLetter(textarrays[i].charAt(0))) { wordNum++; if(!map.containsKey(textarrays[i])) map.put(textarrays[i],1); else { int num=map.get(textarrays[i]); num++; map.put(textarrays[i], num); } } } hotWords=Sort(map); return wordNum; } public static List<HashMap.Entry<String, Integer>> Sort(Map m){ Map<String, Integer> map = new HashMap<String, Integer>(); // 经过ArrayList构造函数把map.entrySet()转换成list List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(m.entrySet()); // 经过比较器实现比较排序 Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Map.Entry<String,Integer> mapping1, Map.Entry<String, Integer> mapping2) { if(mapping1.getValue()==mapping2.getValue()) return mapping1.getKey().compareTo(mapping2.getKey());//字典排序 return mapping2.getValue()-mapping1.getValue();//从大到小 } }); return list; }
对于各个异常状况都会打印异常信息,以下
catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
如图,大部分开销来自于单词技术部分。
共设计了10组测试,分别有普通字符,换行符,空格,单词大小写,控制字符等。
如下是空白文件的测试,分别有统计单词,行数,字符的测试。
如图,在IO上有巨大的开销,主要在计算行数时又访问了一遍文件,致使过分的IO,性能降低,应先将文件数据暂存,后续对该文件进行访问,减小IO,提升性能。
另外分割字符的函数split开销也挺大,或许使用stringTokenizer进行切分能提升性能。
和队友沟通良好,合做愉快!