软工实践之词频统计

Github链接:https://github.com/hizxk/PersonProject-Java2

作业链接:https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1816W/homework/2085


psp表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划2020
• Estimate• 估计这个任务需要多少时间1020
Development开发220340
• Analysis• 需求分析 (包括学习新技术)2020
• Design Spec• 生成设计文档1010
• Design Review• 设计复审1510
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)1520
• Design• 具体设计3045
• Coding• 具体编码210220
• Code Review• 代码复审2025
• Test• 测试(自我测试,修改代码,提交修改)3030
Reporting报告1020
• Test Repor• 测试报告2020
• Size Measurement• 计算工作量1015
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划2020
合计660735

解题思路描述

这道题有四个需求:

  • 统计字符个数
    思路:文本字符可以一个一个读,每读一个就加一
  • 统计单词个数
    思路:将字符串分割,分割出整个字符串的单词字符串:
    1.是可以根据分隔符进行分割,再对分割完的字符串数组进行判断,前四个字符需为英文。

    2.是采用正则表达式,先创建满足条件的正则表达式,让系统去匹配

  • 统计行数
    思路:可以一行一行地读取数据,把一行数据保存在String类中,在判断字符串是否含有有效字符
  • 统计文件中各单词的出现次数,找出频率最高的10个并按字典排序输出
    思路:单词的查找与统计单词个数思想相同,每个单词及其数量可以用map类来存储,map类本身是通过key的 ascill 值来排序,想通过 values 值来排序,可以将map复制到List类中,通过List排序,找出词频最高的10个单词


设计实现过程

实现语言采用java,程序有两个类,一个是Main.java,另一个是lib.java,Main.java是程序的入口,文件写入和打印函数,以及一个文本编码判断函数,lib.java包含一些函数例如字符数计算,单词个数计算,单词统计等,lib.java中的函数全部为静态,因此不需要实例化lib对象,直接使用类.方法即可调用类中的方法,由于功能模块互相独立,因此每调用一次函数,都要读取一次文件。Main.java调用lib.java中的函数并输入计算出的值
1476381-20180909173923475-1098479839.png

字符数计算流程图
1476381-20180912133902431-1297462199.png

单词查找流程图
1476381-20180917204759915-914640465.png


代码说明

  • 文本编码判断
    java在读取文件时需要对文本的编码进行判断,否则可能出现乱码

下表是java编码与txt编码对应表

java编码txt编码
unicodeunicode big endian
utf-8utf-8
utf-16unicode
gb2312ANSI

文本编码会在文本前三个字节说明,因此只要判断前三个字节就可以知道对应的编码

byte[] head = new byte[3];
        String code = "gb2312";
        try {
            InputStream inputStream = new FileInputStream(file);
            inputStream.read(head);
            if (head[0] == -1 && head[1] == -2) {
                code = "UTF-16";
            } else if (head[0] == -2 && head[1] == -1) {
                code = "Unicode";
            } else if (head[0] == -17 && head[1] == -69 && head[2] == -65) {
                code = "UTF-8";
            }
  • 字符个数统计

文件读入通过字节流方式读入 ,每读入一个字符,判断是否是属于ascill字符,满足条件字符数就加一,读取完成的条件为reader.read() != -1

BufferedReader readFile = null;
        int countchar = 0;
        try {
            InputStream is = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(is, code);
            readFile = new BufferedReader(isr);
            while ((readFile.read()) != -1) {
                // if (charTemp / (0x80) == 0) {// 判断是否属于ascill码
                countchar++;
                // }
            }
            readFile.close();
  • 单词统计

首先使用String类中的split函数对字符串进行分割,[^a-zA-Z0-9]+指非英文字符和数字字符,接着使用matches()函数匹配满足单词条件的单词,[a-zA-Z]匹配26个英文字符,{4}指匹配四个英文字符,{a-zA-Z0-9}用来匹配英文和数字字符,*指匹配0个或多个

BufferedReader readFile = null;
        String line = null;
        int countword = 0;
        try {
            InputStream is = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(is, code);
            readFile = new BufferedReader(isr);
            while ((line = readFile.readLine()) != null) {
                String[] words = line.split("[^a-zA-Z0-9]+");
                for (String word : words) {
                    if (word.matches("[a-zA-Z]{4}[a-zA-Z0-9]*")) {
                        countword++;
                    }
                }
            }
            readFile.close();
            isr.close();
            is.close();
  • 词频最高的十个单词

使用map类来保存单词及其数目Map<String, Integer> TheNumberOfWord = new HashMap<String, Integer>();,跟计算单词个数函数一样,构造正则表达式然后匹配符合的字符串,每找到一个先用containsKey函数查找是否已经存在,存在就将values值加一,不存在就置一

while ((line = readFile.readLine()) != null) {
                String[] words = line.split("[^a-zA-Z0-9]+");// 以非英文字符和数字为分隔符
                for (String word : words) {
                    if (word.matches("[a-zA-Z]{4}[a-zA-Z0-9]*")) {// 判断是否满足前四个字符为单词的条件
                        word = word.toLowerCase();
                        if (TheNumberOfWord.containsKey(word)) {
                            TheNumberOfWord.put(word, TheNumberOfWord.get(word) + 1);
                        } else {
                            TheNumberOfWord.put(word, 1);
                        }
                    }
                }
            }

最后是排序查找,将map类的值保存到list类中,再重写比较器进行比较

List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(TheNumberOfWord.entrySet());
        Comparator<Entry<String, Integer>> com = new Comparator<Entry<String, Integer>>() {

            @Override
            public int compare(Entry<String, Integer> arg0, Entry<String, Integer> arg1) {
                // TODO Auto-generated method stub
                if (arg0.getValue() != arg1.getValue()) {
                    return (arg1.getValue().compareTo(arg0.getValue()));
                } else {
                    return (arg0.getKey().compareTo(arg1.getKey()));
                }
            }
        };
        Collections.sort(list, com);

接口性能改进

  • 文本读取到字符串使用 StringBuffer 类取代String,String类是字符串常量,StringBuffer是字符串常量,写入数据速度上来看,StringBuffer大于String,如果是字符串变量的话,尽量用stringbuffer
  • 使用BufferedReader类读取文本数据,读取文本数据瓶颈在IO,采用BufferedReader类将数据读取到内存,减少IO操作,提高数据读取速度

单元测试

通过部分单元测试,暂时未找到问题
1476381-20180910211805210-323761040.png


性能测试

测试软件使用Eclipse Memory Analyzer(这部分不是很懂,只是做了查看)
1476381-20180910205659855-934362935.png


运行代码覆盖率

异常处理的代码占用一些
1476381-20180917205630790-1480133478.png


程序异常处理

程序在运行过程中或多或少会出现一些异常,目前查找到的异常有

异常名称Exception
文件不存在异常FileNotFoundException
文件读写异常IOException

对于异常的发生,采用java异常处理机制:

try{
可能发生异常的代码块
}catch(可以捕获的异常1){
处理异常1的代码
}catch(可以捕获的异常2){
处理异常2的代码
}finally{
处理完所有异常后一定会执行的代码。
在这里注意的事。如果在这里没有出现异常,最终也会执行这行代码
}

捕获到异常就会在控制台打印异常信息:
1476381-20180910212230362-1112158586.png

运行测试

input文件内容
1476381-20180910212724499-1750197167.png
运行结果
1476381-20180912132533747-1335017630.png


心路历程与收获

  • 这次实践学到很多,了解程序读写文件的方法,程序异常处理,关键类的使用方法。同时也感受到程序设计和准备十分重要。
  • 这次单词匹配使用了正则表达式,最近编译原理有学到一些,感觉很有用处,学以致用
  • java在读取文件时最好先判断文本的编码方式,txt文件有四种编码unicode big endian,utf-8,unicode,ANSI,对于不同的编码方式,java也需要采取不同的读取方式
  • 还有适当添加些注释,这个习惯很重要,代码量多,添加一些注释,代码结构更加清晰

转载于:https://www.cnblogs.com/hizxk/p/9594174.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值