这个作业属于哪个课程 | 18级计科-软件工程4班 |
---|---|
这个作业要求在哪里 | 202103226-1 编程作业 |
这个作业的目标 | 熟悉软件开发的实现过程 |
参考文献 | eclipse测试单元、参考等等 |
作业描述
在大数据环境下,搜索引擎,电商系统,服务平台,社交软件等,都会根据用户的输入来判断最近搜索最多的词语,从而分析当前热点,优化自己的服务。首先当然是统计出哪些词语被搜索的频率最高啦,请设计一个程序,能够满足一些词频统计的需求。
需求
-
统计文件的字符数(对应输出第一行):
- 只需要统计Ascii码,汉字不需考虑
- 空格,水平制表符,换行符,均算字符
-
统计文件的单词总数(对应输出第二行),单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。
- 英文字母: A-Z,a-z
- 字母数字符号:A-Z, a-z,0-9
- 分割符:空格,非字母数字符号
例:file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词
-
统计文件的有效行数(对应输出第三行):任何包含非空白字符的行,都需要统计。
-
统计文件中各单词的出现次数(对应输出接下来10行),最终只输出频率最高的10个。
- 频率相同的单词,优先输出字典序靠前的单词。
例如,windows95,windows98和windows2000同时出现时,则先输出windows2000 - 输出的单词统一为小写格式
- 频率相同的单词,优先输出字典序靠前的单词。
Gitee项目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(小时) | 实际耗时(小时) |
---|---|---|---|
Planning | 计划 | ||
Estimate | 估计这个任务需要多少时间 | 0.5h | 1h |
Development | 开发 | ||
Analysis | 需求分析 (包括学习新技术) | 30h | 28h |
Design Spec | 生成设计文档 | 3h | 3.5h |
Design Review | 设计复审 | 1h | 1h |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 0.5h | 0.5h |
Design | 具体设计 | 2h | 2.5h |
Coding | 具体编码 | 10h | 14h |
Code Review | 代码复审 | 1h | 1h |
Test | 测试(自我测试,修改代码,提交修改) | 3h | 4h |
Reporting | 报告 | 2h | 2h |
Test Repor | 测试报告 | 1h | 1h |
Size Measurement | 计算工作量 | 0.2h | 0.1h |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 1h | 1h |
合计 | 55.2h | 59.6h |
解题思路
- 初看到题目只觉得思绪混乱,有很多知识都忘记了,于是仔细看了题目需求之后,大致估计了需要用到的知识,然后拿着以前的教材复习去了;
- 然后根据几个需要的功能,整体的思路是先分别设计几个方法,然后调用,但是对于能用命令行的方式执行这个程序的要求,留到最后解决。
代码规范
设计与实现
- 首先设计一个main方法,通过这个main方法调用读取文件的方法,如下:
String inFileName = args[0];
String outFileName = args[1];
Lib lib = new Lib();
File outFile = new File(outFileName);
try {
if (!outFile.exists())
outFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
- 承载读取出来的文件内容的参数作为输入参数,分别调用对应的实现方法,如下:
charters = lib.CountChar(lib.Readfile(inFileName));
wordsNum = (int)lib.CountWords(lib.Readfile(inFileName));
lines = lib.CountLines(lib.Readfile(inFileName));
lib.CountWordsNum(lib.Readfile(inFileName),wordsNum);
count = lib.GetCount();
words = lib.GetWords();
- 得到的结果作为返回值;再做一个写入文件的方法,按照需求将得到的结果写入一个输出文件中。
fileWriter = new FileWriter(outFile);
fileWriter.write("characters: "+charters+"
");
fileWriter.write("words: "+wordsNum+"
");
fileWriter.write("lines: "+lines+"
");
for (int i=0; i<words.length && count[i]!=0; i++)
fileWriter.write(words[i] + ": " + count[i] + "
");
fileWriter.close();
- 主要功能方法中,统计字符数的方法,调用read()方法逐个以数字的形式读取文本的字符,以ASCII值判断字符
while((charnum=text.read())!=-1) { //text.read()逐个以数字的形式读取文本的字符
if(charnum < 128 && charnum >=0)
number++;
}
- 统计单词数的方法中,单词只由字母或数字组成,且不能由数字开头
while((oneword=text.read())!=-1) {
char ch = (char)oneword;
if(ch >= 'a' && ch <= 'z'
||ch >= 'A' && ch <='Z'
|| ch >= '0' && ch <= '9')
s=s+ch;
else {
if(s != null && Yes(s))
number++;
String t = null;
s = t;
}
}
- 统计有效行数方法,用正则表达式,将只有空白字符的行去掉
while((str = text.readLine()) != null) {
//“\s”是正则表达式,表示所以空白字符(换行、空格等),将这些空白字符换掉
String temp = str.replaceAll("\s","");
if(str.length()!=0)
rows++;
}
- 统计单词频数方法,将符合要求的单词搜寻一次,如果没有相同的,就存入数组中,如果有相同的,则频数加1
while((oneword = text.read())!=-1) {
char ch = (char)oneword;
if(ch >= 'a' && ch <= 'z'
||ch >= 'A' && ch <='Z'
|| ch >= '0' && ch <= '9') {
if(str == null) {
String tem = new String();
str = tem;
}
str=str+ch;
}else {
if(str!="" && Yes(str)) {
String temp = str.toLowerCase();
//单词不在数组中,则存入计数 ,已在数组中,则频数加1
if(!Ifexist(words,temp,counts) && j<words.length) {
words[j] = str;
counts[j]++;
if(j == words.length-1)
break;
j++;
}
str = null;
}
}
- 对单词按频数排序,使用排序的算法,按频数从大到小排列,频数相同时,用compareTo()方法比较两个单词的大小,并排序
if (counts[i]<counts[j]){
//交换两个单词的频数的位置
int temp;
temp = counts[j];
counts[j] = counts[i];
counts[i] = temp;
//交换两个单词的位置
String tempS = new String ();
tempS = words[j];
words[j] = words[i];
words[i] = tempS;
}
else if (counts[i]==counts[j]) {
if (words[i].compareTo(words[j]) > 0){
//交换两个单词的频数的位置
int temp = counts[j];
counts[j] = counts[i];
counts[i] = temp;
//交换两个单词的位置
String tempS = new String ();
tempS = words[j];
words[j] = words[i];
words[i] = tempS;
}
}
改进
对于读取文件的方式,一开始是打算直接用Writer 和Reader类的,然后知道使用到缓冲区会更便捷,于是改成了BufferedReader类;
测试
主要测试Lib中的方法,
- 几个运行的测试
异常处理
基本上对每个方法都进行的
try{
//操作
}catch(Exception e){
//基本错误提示
}
收获
- 一写起代码来就发现有太多知识已经忘记了,然后去翻了教材,主要回顾的还是IO这一章的内容,后续还要继续复习其它的内容;
- 很久没用git了,用起来特别的生疏,查了好多的教程,磕磕绊绊的勉强做好了;
- 以前从来没有接触过测试这一方面,这次突然要用才去查了相应的资料,有一些方法不知道怎么测,但是也写了几个测试,对测试这方面的内容算是有了初步的接触了;
- 代码写的时候觉得没什么问题,写完之后进行测试时才发现有好几个小bug,暂时还没改,等改成了再来更新。