软工实践第二次作业-词频统计
Github:https://github.com/fht2018/PersonProject-Java
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。还有就是读取数据最开始是用字节流读取,字节流是直接对数据本身读取操作。后面该用字符流,字符流是先进行缓存在进行处理。由于是一个一个字节的读取,字节流会频繁的对文件进行操作,而字符流是就能减少一部分开销。
代码说明
Mian类
先读取文件,实例化Count类,调用ccount(),lcount(),wcount()和wordlist()函数分别获取字符数,行数,单词数和单词字典。进行拼接输出到result.txt函数
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException {
//文件输入输出地址
File fileIn = null;
if(args.length>0){
fileIn = new File(args[0]);
}else {
fileIn = new File("D:/softTest/input.txt");
System.out.println("未输入文件名");
System.exit(0);
}
//输出地址
String out_address= "result.txt";
FileOutputStream fileOut = new FileOutputStream(out_address);
//实例化Count类和字符数,行数,单词数,获取单词字典的函数调用
Count count = new Count();
int cnum = count.ccount(fileIn);
int lnum = count.lcount();
int wnum = count.wcount();
List<HashMap.Entry<String, Integer>> wordList= count.wordlist();
//将字符数,单词数,行数结果拼接
String result = "characters:" + cnum + "\r\n" +
"words:" + wnum + "\r\n" +
"lines:" + lnum + "\r\n" ;
//将单词拼接单词
int j = 0;
String t = new String();
if(wordList.size()!=0){
for(;((j<10)&&(j<wordList.size()));j++){
t = "<"+ wordList.get(j).getKey() + ">:" + wordList.get(j).getValue();
result += t + "\r\n";
}
}
//输出到result.txt文件中
fileOut.write(result.getBytes());
fileOut.close();
}
}
Count类
封装字符统计,行数统计,单词数统计函数和生成单词字典
import java.io.*;
import java.util.*;
public class Count {
//初始化全局变量字符数,有效行数,单词数,单词,单词Map
private static int cnum = 0;
private static int lnum = 0;
private static int wnum = 0;
private static String word = new String();
private static Map ma= new HashMap();
//计算字符数
public int ccount(File fileIn){
int len = 0;
try{
//读取文件
BufferedReader bf = new BufferedReader(new FileReader(fileIn));
//给读取的字节码变量赋个初值-1
int byte_char = -1;
//判断一行是否全为空格和“\r”组成,反正行数为有效行
Boolean flag = false;
//开始依次读取字节码
while ((byte_char = bf.read()) >= 0 ){
cnum++;
//如果非空格和“\r\n”,当前行有效行标志flag变为true
if((byte_char != 10)&&(byte_char != 13)&&(byte_char != 32)){
flag = true;
}
//如果是空格或者“\r”
else if ((byte_char == 10)||(byte_char == 32)){
}
//如果是“\n”
else if(byte_char == 13){
if(flag){
lnum++;
flag = false;
}
}else{
flag = true;
}
len = Count.judge(byte_char,len,ma);
}
//全都读取完,最后一个如果是符合要求的单词,随便输入一个非字母数字的字节码进行单词截断
len = Count.judge(13,len,ma);
bf.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//以“\n”+flag判断有效行数会缺少第一行
lnum++;
return cnum;
}
//输出全局变量行数
public int lcount(){
return this.lnum;
}
//输出全局变量单词数
public int wcount(){
return this.wnum;
}
//单词排序
public List<HashMap.Entry<String, Integer>> wordlist(){
List<HashMap.Entry<String, Integer>> wordList = WordSort();
return wordList;
}
//检测单词的函数
public static int judge(int byte_num, int len, Map m){
if(len>=4){
if((byte_num>=65&&byte_num<=90)){
word = word + (char)(byte_num+32);
len++;
}else if((byte_num>=97&&byte_num<=122)||(byte_num>=48&&byte_num<=57)){
word = word+ (char)(byte_num);
len++;
}else{
ma = Maps(m,word);
wnum++;
word = new String();;
len = 0;
}
return len;
}else{
if(byte_num>=65&&byte_num<=90){
word = word+ (char)(byte_num+32);
len++;
}else if(byte_num>=97&&byte_num<=122){
word = word+ (char)(byte_num);
len++;
}else{
word = new String();;
len = 0;
}
return len;
}
}
//更新字典的函数
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>> WordSort(){
List<HashMap.Entry<String, Integer>> wordList = new ArrayList<HashMap.Entry<String, Integer>>(ma.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;
}
}