软工实践第二次作业-词频统计
题目地址:https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1816W/homework/2085
Github:https://github.com/fht2018/PersonProject-Java2
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 450 | 660 |
• Estimate | • 估计这个任务需要多少时间 | 450 | 660 |
Development | 开发 | 650 | 970 |
• Analysis | • 需求分析 (包括学习新技术) | 30 | 50 |
• Design Spec | • 生成设计文档 | 20 | 30 |
• Design Review | • 设计复审 | 80 | 120 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
• Design | • 具体设计 | 80 | 140 |
• Coding | • 具体编码 | 360 | 460 |
• Code Review | • 代码复审 | 20 | 30 |
• Test | • 测试(自我测试,修改代码,提交修改) | 30 | 200 |
Reporting | 报告 | 60 | 70 |
• Test Repor | • 测试报告 | 10 | 10 |
• Size Measurement | • 计算工作量 | 20 | 20 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 710 | 1040 |
解题思路描述
答:一看到题目使用c++或者java,一下就选择最近在学习的java。大概浏览了一下要求,打算先设计核心功能之后再实现细节比如命令行,分装函数什么的。大概就是读取文本信息,依次判断字节码范围判断字符数,以“\n”为行首判断行数在加上第一行,同时依次判断是否是单词,并有一个函数来处理字典。
设计实现过程
答:核心功能就大概是字符统计,单词统计(自定义单词,至少4字母开头的字母数字组合),有效行数统计。
所以先获取数据,到网上查了一下java字符流读取文件,读取到数据后就开始处理,通过一个一个字符的遍历,判断字符的字节码在0到127的,超过的忽略(忽略汉字及其他字符)。定义一个word的全局变量存放单词,和一个全局变量len存单词的长度,写一个judge函数把字符依次送入判断,如果符合单词的要求,把获得的单词送入一个更新字典的函数。最后把数据拼接在一起,输出到result.txt。进行简单测试之后,将核心功能函数分装到Count类中。
改进思路
答:在for循环中,第一个参数变量i,定义int i在循环外面比循环里面性能稍微好一些,避免每次循环都进行定义一个i。还有就是读取数据最开始是用字节流读取,字节流是直接对数据本身读取操作。后面该用字符流,字符流是先进行缓存在进行处理。由于是一个一个字节的读取,字节流会频繁的对文件进行操作,而字符流是就能减少一部分开销。
代码说明
定义一个Count类,在里面依次封装字符统计,有效行数统计,单词统计等函数。在构造函数中读取文件里的信息
//构造函数
public Count(File fileIn) {
try{
//读取文件,注意要以utf8格式读取,不然cmd编译和编译器编译出来的读取字符数会有偏差
BufferedReader bf = new BufferedReader(new InputStreamReader(new FileInputStream(fileIn),"utf8"));
//用StringBuffer依次存每个字符
StringBuffer contents = new StringBuffer();
int byte_char = -1;
//开始依次读取字节码
while ((byte_char = bf.read()) >= 0) {
contents.append((char)byte_char);
}
content = contents.toString();
bf.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//字符统计函数,先把"\r\n"全部替换成"\n",防止回车在不同的编码环境下被统计为2个字符
public int charactersCount(){
String clearcontent = content.replaceAll("\r\n","\n");
int charactersnum = clearcontent.length();
return charactersnum;
}
//有效行数统计函数,以"\n"判断行数,设置flag判断是否为空字符
public int lineCount(){
Boolean flag = false;
int linenum = 0;
int i = 0;
for (;i<content.length();i++){
if(content.charAt(i) != '\r' && content.charAt(i) != '\n' && content .charAt(i) != ' ' ){
flag = true;
}else if(content.charAt(i) == '\n'){
if(flag){
linenum++;
flag = false;
}
}
}
if(flag){
linenum++;
}
return linenum;
}
//单词统计函数,将大写字母转为小写字母,再将所有非字母数字的字符替换为“|”,通过“|”切割单词,在判断单词是否符合四个字母开头的要求,符合的话存进字典
public int wordCount(){
int wordNum = 0;
String regex = "[^0-9A-Za-z]";
String contentString = content.toLowerCase().replaceAll(regex,"|");
String[] contents = contentString.split("\\|");
int i = 0;
for (; i <contents.length ; i++ ) {
if(contents[i].length()>=4){
if(Character.isLetter(contents[i].charAt(0))){
if(Character.isLetter(contents[i].charAt(1))){
if(Character.isLetter(contents[i].charAt(2))){
if(Character.isLetter(contents[i].charAt(3))){
wordNum++;
Maps(ma,contents[i]);
}
}
}
}
}
}
if(!ma.isEmpty()){
words = Sort(ma);
}
return wordNum;
}
//更新字典的函数,将符合的单词存进全局静态变量字典中
public static Map Maps(Map m, String s){
if(m.containsKey(s)){
int n = (int)m.get(s);
n++;
m.put(s,n);
}else{
m.put(s,1);
}
return m;
}
//单词排序函数,将字典依次按照出现次数排序,次数相同的按字典序排序
public static List<HashMap.Entry<String, Integer>> Sort(Map m){
List<HashMap.Entry<String, Integer>> wordList = new ArrayList<HashMap.Entry<String, Integer>>(m.entrySet());
Comparator<Map.Entry<String, Integer>> com = new Comparator<Map.Entry<String, Integer>>(){
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
if(o1.getValue()==o2.getValue())
return o1.getKey().compareTo(o2.getKey());//字典序
return o2.getValue()-o1.getValue();//从大到小
}
};
wordList.sort(com);
return wordList;
}