zoukankan      html  css  js  c++  java
  • 词频统计

    • 作业地址:

    https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1816W/homework/2085

    一、Github地址

    https://github.com/xshl/PersonProject-Java2

     二、PSP表格

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

    三、解题思路&学习历程

    • 解题思路

    刚拿到题目的时候没什么头绪,第一反应就是去遍历。事实上我也是这么做的

      • 统计文件的字符数(charCount.java)
        • 根据编码判断每个字符是不是我们所需要的。
        • 由于换行符占两个字符但是在我们计算的时候换行符只算一个字符,所以最终的字符数要减去行数才是最终的数量。
      • 统计文件的单词总数
        • 根据分隔符进行单词分割,并判断是否符合单词要求。
        • 但是存在一个问题,分割符是列举的,会存在遗漏现象。
        • 采用正则表达式
      • 统计文件的行数
        • 通过readLine()获取行数
        • 并识别换行符
      • 统计单词频率,并输出频率最高的10个
        • 在分割出单词之后,将单词遍历储存在hashmap当中,在储存前先判断是否为合法单词
        • 将map的遍历储存在set当中
    • 学习历程

    在决定用java书写之后,就把之前借的疯狂Java讲义翻了出来,看了下如何读和写txt。对于map的排序问题,看了csdn上的一些博客,然后通过自己的理解,写出了统计频率的函数。

      • 学习JAVA hashmap的使用以及排序
      • 学习正则表达式(但还没用)

     

    四、计算模块接口的设计与实现过程

    Main.java函数调用其它函数实现相应的功能

    • 统计文件的字符数(charCount.java)

     1 while((value = bReader.read()) != -1) {
     2     if (value >= 0 && value<=255) {
     3         charcount++; 4     }
     5 }
    • 统计文件的单词总数(wordCount.java)
    1 while ((line = bufferedReader.readLine()) != null) {
    2     String[] words = line.split("[^a-zA-Z0-9]+");
    3     for (String word : words) {
    4         word.toLowerCase();
    5         if (word.matches("[a-zA-Z]{4}[a-zA-Z0-9]*") ) {
    6             countword++;
    7         }
    8     }
    9 }
    • 统计文件的行数

    1 while ((line = bufferedReader.readLine()) != null) {
    2       if (line.length() != 0 && !line.matches("\s+")) {
    3             linecount++;
    4       }
    5
    • 统计单词频率,并输出频率最高的10个
      • 在分割出单词之后,将单词遍历储存在hashmap当中,在储存前先判断是否为合法单词
    String str=st.nextToken();
    str = str.toLowerCase();
    if ((str.charAt(0) >= '9' || str.charAt(0) <= '0') && str.length() >= 4) {
        if(map.containsKey(str)) 
            map.put(str, map.get(str)+1);
        else map.put(str, 1);
    }
      • 将map的遍历储存在set当中
    Set<WordEntity> set=new TreeSet<WordEntity>();
    for(String s:map.keySet()){
         WordEntity wordEntry=new WordEntity(s,map.get(s));
         set.add(wordEntry);     
    }
    Iterator<WordEntity>  ite=set.iterator();
    int count=0;
    while(ite.hasNext()){
    if(count>=10) 
         break;
       System.out.println(ite.next());
       count++;
    }

    五、计算模块接口部分的性能改进

    从最初的暴力解决一步步改善用hashmap存储对单词的遍历,map的遍历存储在set中,排序 TreeSet,对wordEntity实现comparable接口重写compareTo()和toString()。

     1 @Override
     2 public String toString() {
     3     writeInTxt.writeTxt( "<" + word + ">:" + count);
     4     return "<" + word + ">:" + count;
     5 }
     6 @Override
     7 public int compareTo(WordEntity O) {
     8     int cmp=count.intValue()-O.count.intValue();
     9     return (cmp==0?word.compareTo(O.getKey()):-cmp);
    10 }

     接口:

     1 public interface WordCount {
     2     
     3     /**
     4      * 返回行数
     5      * @param filename
     6      * @return
     7      * @throws IOException
     8      */
     9     int linesCount(String filepath) throws IOException;
    10     
    11     /**
    12      * 返回合法单词数
    13      * @param filepath
    14      * @return
    15      * @throws IOException
    16      */
    17     int wordsCount(String filepath) throws IOException;
    18     
    19     /**
    20      * 返回字符数
    21      * @param filepath
    22      * @return
    23      * @throws IOException
    24      */
    25     int charsCount(String filepath) throws IOException;
    26     
    27     /**
    28      * 词频前十的单词
    29      * @param filepath
    30      * @throws IOException
    31      */
    32     void wordDetail(String filepath) throws IOException;
    33 }

     

    六、计算模块部分单元测试展示

    • 通过单元测试,暂时未发现bug
      • 测试数据

      • 测试结果

     

    • 补充(9月13日):在进行单元测试时未发现bug。

    • 代码覆盖率,其中未覆盖到的大部分为异常处理

    • 其中wordDetail.java耗时最长,因为在这个函数中涉及了排序

     

    七、计算模块部分异常处理说明

    try{
        可能发生异常的代码块
    }catch(异常1){
        处理异常1的代码
    }


    七、感悟

    之前接触JAVA都是在Android开发和上学期的数据库作业中,原本觉得做起来会轻松一点,但是在这次的实践中做的很吃力,而且效果也很不理想,对一些JAVA的知识了解的还不够深,想HashMap、TreeSet等,花了很多时间在查资料和学习上,比自己预计的时间多了很多,接下来还是要好好学习基础。在以前使用JAVA写项目的时候,都没有尝试过做单元测试,平常找错都是讲结果输出看,这次做单元测试也是查了网上的资料,再慢慢尝试。代码还存在一个问题,运行之后在将结果写入result.txt之后不会清除之前的记录,只会添加。


    更新(9.13)

    运行结果写入result.txt之后不会清除之前的记录问题已解决。在Main函数中添加以下代码。由于之前是在writeInTxt中写这段代码,导致每次调用writeInTxt时都清除了一遍,只显示最后一个写入的。

    File file1 = new File(".\result.txt");
    if (file1.exists() && file1.isFile()) {
        file1.delete();
    }

    补充:在提交的时候只测试了自己的样例,单词句子数量比较少,没有出错。提交的是使用比较暴力的分割方法做的,接下来打算采用正则表达式进行改善,已用正则改善。

  • 相关阅读:
    Dao层
    I/O流
    导入第三方jar包
    怎么使用log4j
    JDBC访问数据库的步骤
    抽象和封装
    JDBC中PreparedStatement接口提供的execute、executeQuery和executeUpdate之间的区别及用法
    ResultSet next方法
    实体类(entity)的作用
    接口的作用
  • 原文地址:https://www.cnblogs.com/xsl-/p/9634204.html
Copyright © 2011-2022 走看看