编程作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/computer-science-class4-2018/
这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/computer-science-class4-2018/homework/11880
这个作业的目标 能够实现统计文本文档词频的控制台程序,进行代码优化,完成代码完成词频统计个人作业,实现要求。
其他参考文献 《构建之法》、《现代软件工程》、CSDN、博客园、Git

1、项目链接(https://gitee.com/kckr/project-java/tree/master/20188527)

2、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 20
• Estimate • 估计这个任务需要多少时间 15 20
Development 开发 400 460
• Analysis • 需求分析 (包括学习新技术) 40 60
• Design Spec • 生成设计文档 20 20
• Design Review • 设计复审 10 15
• Coding Standard • 代码规范 (为目前的开发制定合适的规范) 20 25
• Design • 具体设计 20 20
• Coding • 具体编码 200 220
• Code Review • 代码复审 30 30
• Test • 测试(自我测试,修改代码,提交修改) 60 70
Reporting 报告 70 90
• Test Repor • 测试报告 45 60
• Size Measurement • 计算工作量 10 10
• Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 15 20
合计 485 570

3、解题思路描述

仔细阅读完作业题目要求后,发现题目要实现6个功能,具体需求为:

1.读取txt文件中的内容
2.统计文件的字符数
3.统计文件的单词总数
4.统计统计文件的有效行数
5.统计文件中各单词的出现次数,并输出频率最高的10个
6.将输出结果写入txt文件

分析完需求后,问题首先要解决的就是如何进行文件的读写
针对第二个需求统计文件的字符数,我首先想到的就是采用一个字符一个字符的读取文件内容,这样可以更好的对每一个字符进行判断。而后的几个需求,我认为采用行方式读取文件内容,对于功能的实现会简单些。

对于第三个需求,我的想法是将文件每行的内容采用分割法,以非字母、数字的分割符将其分割保存在数组中,在对每个划分后的词进行判断是否为有效单词,但这个分割的方法一开始让我无从下手,后面在CSDN上查找资料发现了正则表达式,这样单词的分割就简单了许多。

第四个需求也是对文件的每行单独判断,想着尝试将字符串中的空字符以空字符串代替,后面查找资料发现了replaceAll("s*","")方法。

针对第五个需求,采用同需求三一样的方法先划分单词,然后再将有效单词转换为小写保存在Map中,每次有效单词出现就先判断是否存在,存在则将value+1,否则就存入新的有效单词。词频的统计我是在CSDN上查找了Map<String,Integer>的排序方法,并且修改排序规则从而实现的。

4、代码规范制定链接

myCodeStyle(https://gitee.com/kckr/project-java/blob/master/20188527/src/codestyle.md)

5、设计与实现过程

根据程序功能要求,划分为一个主函数,两个类

WordCount 主函数
FileIO 实现文件的读取,以及将结果写入文件
DoWordCount 实现字符、单词、函数、单词词频的计算

countChars调用getReader,得到其返回的Reader进行以单个字符形式的文件读取
countWords、countLines、sortWords的参数皆为readFile返回的ArrayList
countWords中在判断是否为有效单词时,调用了isValidWord函数,isValidWord函数中判断单词前四位是否为字母时调用了isAlpha函数
printTop10的参数为sortWords函数Map排序后返回的List<Map.Entry<String, Integer>>

7、关键代码

  //统计字符数,空格,水平制表符,换行符,均算字符
    while ((tempChar = reader.read()) != -1) {
        sum++;
    }

在单词分割上,我使用了正则表达式(这应该就是我这代码里面唯一的独到之处了) ,使用非字母和数字来分割文件内容的每一行,在对分割后的单词逐一进行判断,调用isValidWord(word)方法判断其长度是否满足要求,isValidWord(word)方法里面又调用了isAlpha()方法判断前四位是否为字母。

 for (int i = 0; i < lines.size(); i++) {
            line = lines.get(i);
            words = line.split("[^a-zA-Z0-9]+");
            for (int j = 0; j < words.length; j++) {
                char[] word = words[j].toCharArray();
                if (isValidWord(word)) {
                    sum++;
                }
            }
        }

将文件的每一行中的空白符以空字符串代替,在将其与空字符串比较,若非空,则为有效行。

for (int i = 0; i < lines.size(); i++) {
            line = lines.get(i);
            line = line.replaceAll("\s*", "");
            if (!(line.equals(""))) {
                sum++;
            }
        }

同前面一样,先判断是否为有效单词,若有效,将其转换为小写,然后使用map进行储存,因为map的key不可重复,所以每次写入前判断map之前是否存在过该数据,若没有存在过,则该value值为1,否则,在其value值上再加1.最后将map改为list存储,再用Collections.sort进行排序,通过重写comparator来实现要求的排序,当单词的数量一致时,则比较单词在字典序的先后。

if (isValidWord(word)) {
        tempWord = words[j].toLowerCase();
        if (!map.containsKey(tempWord)) {
            map.put(tempWord, Integer.valueOf(1));
        } else {
            map.put(tempWord, Integer.valueOf(map.get(tempWord).intValue() + 1));
        }
    }
List<Map.Entry<String, Integer>> mappingList = new ArrayList<>(map.entrySet());
    //通过比较器实现比较排序
    Collections.sort(mappingList, new Comparator<Map.Entry<String, Integer>>() {
        @Override
        public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
            if (o1.getValue().equals(o2.getValue())) {
                return o1.getKey().compareTo(o2.getKey());
            } else {
                return o2.getValue().compareTo(o1.getValue());
            }
        }
    });

8、异常处理说明

异常处理命令行参数无输入/输出文件的情况:

if(args.length!=2){
        System.out.println("参数输入个数有误,请重新输入");
        return ;
    }

输出文件不存在时,系统会自动创建输出文件。
剩余的输入流异常,抛出到最外面同一处理。

9、心路历程与收获

在这次的作业中,我学到了很多编写代码以外其他的很多内容,也更加体会到了软件工程这门课的重要性。接触了Git和Gitee,并了解了如何使用gitee发布项目和控制版本,不在只是停留在纸面上的认识,一旦项目有进展便签入Gitee,也使我更加深刻感到它带来的好处。在此次的实践中,我也学会了按照PSP表格对项目进行一步一步的构建完成,不像之前一股脑就开始进入编程阶段,按照这样的方式写出来的程序可靠性也要来的强得多。并且在此次的作业中,也严格规范了自己的代码风格,对我来说有又是一次成长。虽然一开始感觉好多东西都在我的知识盲区中,但是每次作业的完成,对未知知识的探索,都是一次极好的体验。

原文地址:https://www.cnblogs.com/freezinng/p/14611037.html