• 情 202103226-1 编程作业


    这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/computer-science-class3-2018/homework/11879
    这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/computer-science-class3-2018/homework/11879
    这个作业的目标 学会使用gitee并且完成词频统计编程
    学号 20188474

    Github项目地址

    2、PSP表格

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

    3、解题思路描述
    设计一个Lib类,在其中设计所需的方法,WordCount类有一个main()函数,调用Lib的方法实现功能。
    代码运行流程和思路:
    打开输入文件并读取内容:看到文件读写首先就在想要用哪种读写方式,后来选择使用BufferedReader,read()方法读取文件内容,并且不读取' '
    统计字符数:因为不考虑中文字符,且任意ASCII码均算做一个字符,所以觉得只要读取读取内容的长度就可以了。
    统计单词数:刚开始想到split()方法来分割单词,但还在犹豫分割的方式,后来在网上查询到了正则表达式,于是就利用正则表达式将内容分成单词数组并检验单词的合法性,统计数量。
    统计非空行数:同样利用正则表达式的方法。
    统计频率最高的单词:在统计单词数时将单词信息存放到Map<String, Integer>中,然后对Map内容进行排序。
    将内容写入输出文件:使用BufferedWrite,write()方法,分别将所需内容写入文件。
    4、代码规范制定链接

    5、设计与实现过程
    类设计
    Lib类和WordCount类:
    其中Lib封装了具体功能的实现方法,WordCount只有一个main函数,调用Lib类封装的方法。
    Lib类主要属性和方法有:
    ` private String inputFile;
    private String outputFile;
    private String content;
    private int charsNum;
    private int wordsNum;
    private int linesNum;
    private Map<String, Integer> wordsMap;

    /**
     * 读取文件内容
     */
    public void readFile() throws IOException
    
    /**
     * 写入文件
     */
    public void writeFile() throws IOException
    
    /**
     * 统计字符数
     */
    public void countCharsNum()
    
    /**
     * 统计单词数,以及每个单词出现的次数
     */
    public void countWordsNum()
    
    /**
     * 统计非空行数
     */
    public void countLinesNum()
    
    /**
     * 根据单词频率进行排序
     */
    public List<Map.Entry<String, Integer>> sortWordsMap()`
    

    函数关系图:

    功能实现
    统计字符数
    由于不考虑中文字符,且任意ASCII码均算做一个字符,在文件读入时就除去了' ',所以直接获取字符串长度即可
    charsNum = content.length();
    统计单词数,在统计单词数的同时,可以一起记录单词以及出现的次数
    使用正则表达式和split()方法,将读取的字符串内容以空格,非字母数字符号分割,且使用toLowerCase()全部转化为小写
    String[] words = content.split("[^a-zA-Z0-9]+");
    使用正则表达式,来验证分割后的字符串是否符合单词的定义(至少以4个英文字母开头,跟上字母数字符号)
    if (words[i].matches("[a-zA-Z]{4,}[a-zA-Z0-9]*")) {
    wordsNum++;
    使用Map<String, Interger>存放单词与次数
    word = words[i].toLowerCase(); if (wordsMap.containsKey(word)){ num = wordsMap.get(word); num++; wordsMap.put(word, num); } else { wordsMap.put(word, 1); }
    统计有效行数
    任何包含非空白字符的行,都需要统计,所以使用正则表达式来匹配
    linesNum = 0; Pattern linePattern = Pattern.compile("(^| )\s*\S+"); Matcher matcher = linePattern.matcher(content); while (matcher.find()){ linesNum++; }
    因为结果要输出频率最高的10个单词,所以对单词Map进行排序
    频率相同的单词,优先输出字典序靠前的单词。
    List<Map.Entry<String, Integer>> wordsList = new ArrayList<Map.Entry<String, Integer>>(wordsMap.entrySet()); Collections.sort(wordsList, new Comparator<Map.Entry<String, Integer>>() { public int compare(Map.Entry<String, Integer> word1, Map.Entry<String, Integer> word2) { if(word1.getValue().equals(word2.getValue())) { return word1.getKey().compareTo(word2.getKey()); } else { return word2.getValue() - word1.getValue(); } } });
    读文件选择使用BufferedReader、read()方法,使用StringBuilder来合并每次读到的字符,提高性能,并且不读取' '
    while ((num = reader.read()) != -1) { // UTF-8中' '对应编码int值为13 if (num != 13) { ch = (char) num; builder.append(ch); } }
    写文件选择了BUfferedWrite、write()方法
    6、性能改进
    文件读取的方式使用了带缓冲的BufferedReader和BufferedWrite,提高了读写效率。
    对于求出频率最高的10个的单词的问题上,原先是使用TreeMap存放单词及其出现次数,因为TreeMap是有序的,但是发现如果是在大数据的情况下,插入的次数很多,所以改成了使用HashMap。
    7、单元测试
    以下展示代码均为关键代码,省略了构造字符串、文件读写等内容

    测试统计字符数
    需要考虑Ascii码,空格、水平制表符、换行符等都需要考虑在内,比如:"aaaa b8 c "
    String testStr = "aaaa b8 c\t\r\n "; // 省略构造字符串、字符串写入文件等代码 ...... assertEquals(testStr.length(), lib.getCharsNum());
    测试统计单词数
    需要考虑单词至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。比如:"windows95 windows98 file,123file File windows2000 "
    String str = "windows95 windows98 file,123file File windows2000 "; int num = 4 int loopTimes = 200; // 可使用循环增加测试量 ...... assertEquals(num * loopTimes, lib.getWordsNum());
    测试统计有效行数
    任何包含非空白字符的行,都需要统计,比如:"hello]w666 word file1file "
    String str = "hello]w666 word file1file "; int num = 2; int loopTimes = 100; // 数据处理 ...... assertEquals(num * loopTimes, lib.getLinesNum());
    测试统计频率前十的单词
    输出的单词统一为小写格式,频率相同的单词,优先输出字典序靠前的单词。
    final String[] words = {"aaaa1","bbbb2","cccc3","dddd4","eeee5", "ffff6", "gggg7", "HHHH8", "OoOo9", "pPpP10", "qqqq11"}; // 数据处理 ...... int i = 10; for(Map.Entry<String, Integer> map : topWords) { assertEquals(map.getKey(), words[i]); i--; }
    测试频率前十单词的排序
    final String[] words = {"aaaa10","aaaa13","aaaa23","aaaa4","bbbb5", "bbbb6", "bbbb66", "cccc", "cccc3", "cccc38", "cccc4"}; // 数据处理 ...... int i = 0; for(Map.Entry<String, Integer> map : topWords) { assertEquals(map.getKey(), words[i]); i++; }
    测试覆盖率

    因为Lib中有个get函数测试时没有用上,还有一些ctach语句块里的异常处理语句,所以Method和Line的覆盖率不是100%
    8、异常处理说明
    Lib中的异常都是I/O异常。
    WordCount类中,对文件传入参数个数进行了异常处理
    if (args.length < 2){ System.out.println("Insufficient parameters"); } else { ...... }

    9、心路历程与收获
    此次作业第一次接触使用了git,学习了如何使用,也感受到了用git工具管理代码的优越性。但是在使用过程中也不是一帆风顺的,有时候写错单元测试的代码,导致也无法找到错误。

  • 相关阅读:
    Vue中axios基础使用(一)_前端前端请求数据
    vue中使用font-awesome
    vue-cli 搭建项目中,img引用资源404
    前端工程化常用的基础lunix命令
    vue运行项目时network显示unavailable
    关于vue中node_modules中第三方模块的修改使用
    tableau extension 调研
    使用 certbot 自动给 nginx 加上 https
    前端常用:复制到剪切板和下载
    ssh 的一个坑
  • 原文地址:https://www.cnblogs.com/shsy/p/14615157.html
Copyright © 2020-2023  润新知