一.需求分析
根据实验二软件工程个人项目所提要求进行分析后可知用户的需求主要有:
1.程序可读入任意英文文本文件,该文件中英文词数大于等于1个。
2.程序需要很壮健,能读取容纳英文原版《哈利波特》10万词以上的文章。
3.指定单词词频统计功能:用户可输入从该文本中想要查找词频的一个或任意多个英文单词,运行程序的统计功能可显示对应单词在文本中出现的次数和柱状图。
4.高频词统计功能:用户从键盘输入高频词输出的个数k,运行程序统计功能,可按文本中词频数降序显示前k个单词的词频及单词。
5.统计该文本所有单词数量及词频数,并能将单词及词频数按字典顺序输出到文件result.txt。
二.功能设计
基本功能
1.用户输入任意多个英文单词,显示对应单词在文本中出现的次数和柱状图。
2.用户从键盘输入高频词输出的个数k,按文本中词频数降序显示前k个单词的词频及单词。
3.统计该文本所有单词数量及词频数,并能将单词及词频数按字典顺序输出到文件result.txt。
扩展功能
4.输入一个文件的文件路径及文件名可以找到该文件并对该文件中的文本进行单词分解和单词词频统计。
三.设计实现
在该词频统计软件中,只有一个类Main.java,该类中在主函数main中用hashMap的数据结构、StringTokenizer方法来分词并且统计词频;
在子函数queryWord中使用字符串的split分割方法以及字符串数组遍历的方式找出用户所需查询的单词对应的词频,通过保留各单词词频占用户查询所有词词频的比例来绘制响应的柱状图;
在子函数sortMapByValues中使用set、LinkedList及Entry等数据结构根据hashMap的值进行排序后根据用户所输入的k值输出频率最高的前K个单词;
在子函数sortMapByKeys中使用与sortMapValues函数异曲同工的方式根据hashMap的键按照字母表顺序进行排序后存放到当前目录下的result.txt文件中;
最后在主函数中依次调用这三个子函数,实现所有具体功能。
四.测试运行
经过反复测试与调试之后的最终结果如下图所示:
五.独特代码片段秀
分割文本中的单词,统计相应词频
// 用正则表达式来过滤字符串中的所有标点符号
String regex = "[【】、.。,,。\"!--;:?\'\\]]";
try {
// 读取要处理的文件
System.out.println("请输入读取文件的文件名:");
String s = in.nextLine();
BufferedReader br = new BufferedReader(new FileReader(s));
String value;
while ((value = br.readLine()) != null) {
value = value.replaceAll(regex, " ");
// 使用StringTokenizer来分词
StringTokenizer tokenizer = new StringTokenizer(value);
while (tokenizer.hasMoreTokens()) {
String word = tokenizer.nextToken();
if (!hashMap.containsKey(word)) {
hashMap.put(word, new Integer(1));
} else {
int k = hashMap.get(word).intValue() + 1;
hashMap.put(word, new Integer(k));
}
}
}
对用户输入的字符串进行分割
System.out.println("请输入需要查询的单词,单词之间用空格隔开");
String s = in.nextLine();
String[] word= s.split(" ");
根据hashMap的值进行排序
Set<Entry<String,Integer>> mapEntries = Map.entrySet();
LinkedList<Entry<String, Integer>> List = new LinkedList<Entry<String,Integer>>(mapEntries);
// 根据映射的值对列表排序
Collections.sort(List, new Comparator<Entry<String,Integer>>() {
@Override
public int compare(Entry<String, Integer> ele1, Entry<String, Integer> ele2) {
return ele2.getValue().compareTo(ele1.getValue());
}
});
根据hashMap的键进行排序
Set<Entry<String,Integer>> mapEntries = Map.entrySet();
LinkedList<Entry<String, Integer>> List = new LinkedList<Entry<String,Integer>>(mapEntries);
// 根据映射的键对列表排序
Collections.sort(List, new Comparator<Entry<String,Integer>>() {
@Override
public int compare(Entry<String, Integer> ele1, Entry<String, Integer> ele2) {
return ele1.getKey().compareTo(ele2.getKey());
}
});
将排序好的单词与词频的映射存放到文件中
File file = new File("result.txt");
try {
if(file.exists()) {
file.createNewFile();
}
FileWriter fop = new FileWriter(file.getAbsoluteFile());
for(Entry<String,Integer> entry : Map2.entrySet()) {
fop.write(entry.getKey()+":\t"+entry.getValue()+"\n");
}
fop.close();
System.out.println("存放结束,请在当前目录下查看!");
}catch(IOException e) {
e.printStackTrace();
}
六.总结
在这次的词频统计软件开发过程中,主要将该软件分成三大模块:文本的单词提取和词频统计、单词匹配后输出、根据单词词频排序后输出用户需要查看的k个、根据单词字母表顺序排序后保存在文件中。第一个模块在主函数中实现,而后面三个模块分别通过三个子函数来实现,之后在主函数中被调用,以此来达到软件设计的“模块化”原则。
PSP展示
任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
计划 | 8 | 5 |
估计这个任务需要的时间,并规划大致工作步骤 | 8 | 5 |
开发 | 100 | 105 |
需求分析(包括学习新技术) | 6 | 8 |
生成设计文档 | 10 | 15 |
设计复审 | 6 | 5 |
代码规范(为目前的开发制定合适的规范) | 3 | 3 |
具体设计 | 10 | 12 |
具体编码 | 50 | 65 |
代码复审 | 10 | 11 |
测试(自我测试、修改代码、提交修改) | 15 | 17 |
报告 | 9 | 7 |
测试报告 | 3 | 3 |
计算报告量 | 1 | 2 |
事后总结,并提出过程改进计划 | 5 | 4 |
从PSP表中可以看出在具体编码这一环节耗时最多而且计划时间和实际时间之间的差距比较大,这是因为很久没有练习,需要在网上和教材上搜集相关知识点并重温,所以耗时较多。因此在后面的学习中,还需要勤加练习,更加熟练的掌握知识点,然后更好的运用到自己的学习当中。
该词频统计软件源码可在此处查看