zoukankan      html  css  js  c++  java
  • 编程作业

    这个作业属于哪个课程 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表格对项目进行一步一步的构建完成,不像之前一股脑就开始进入编程阶段,按照这样的方式写出来的程序可靠性也要来的强得多。并且在此次的作业中,也严格规范了自己的代码风格,对我来说有又是一次成长。虽然一开始感觉好多东西都在我的知识盲区中,但是每次作业的完成,对未知知识的探索,都是一次极好的体验。

  • 相关阅读:
    AJPFX总结java开发常用类(包装,数字处理集合等)(三)
    AJPFX总结java开发常用类(包装,数字处理集合等)(二)
    AJPFX总结java开发常用类(包装,数字处理集合等)(一)
    AJPFX关于面向对象之封装,继承,多态 (下)
    AJPFX关于面向对象之封装,继承,多态 (上)
    Android IntentFilter匹配规则
    细说Activity与Task(任务栈)
    androidStudio 打包与混淆
    Android activity之间的跳转和数据传递
    android开发中的 Activity 与 Context 区别与联系
  • 原文地址:https://www.cnblogs.com/freezinng/p/14611037.html
Copyright © 2011-2022 走看看