zoukankan      html  css  js  c++  java
  • 第一次个人编程作业

    作业链接

    一、PSP表格

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

    二、计算模块接口

    1.计算模块接口的设计与实现过程

    设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。

    代码组织
    包括以下2个类:

    WordMap类 - 构建DFA树

    • addToWordSet函数 - 将敏感词放入到HashSet中
    • initWordMap函数 - 初始化敏感词库

    Tool类 - 使用DFA树以及拼音、部首的转化

    • getPyWord函数 - 中文敏感词拼音替代、拼音首字母替代
    • initDictMap函数 - 初始化部首字典
    • getBsWord函数 - 中文敏感词部首拆分
    • checkKeyword函数 - 敏感词检测

    关键算法
    关键函数有敏感词检测checkKeyword函数、getPyWord函数、getBsWord函数等。
    其中getPyWord函数主要调用库来实现(jpinyin.jar是我目前找到最全的),getBsWord函数主要是添加汉语拆字的字典,来检测偏旁部首拆分。
    而checkKeyword函数采用了DFA算法 ,即确定有穷自动机,通过动作和当前状态得到下一个状态,即event+state=nextstate。在实现敏感词过滤的过程中,我们必须要减少运算,而DFA在DFA算法中几乎没有什么计算,只有状态的转换。
    实现DFA算法的流程为:

    • 词库整理:将敏感词放入到HashSet中
    • 构建DFA树:详见下面的流程图
    • DFA树的使用:逐个检测目标词中的字,最后一个字在树中且满足isEND=1,则是敏感词

    构建DFA树流程图

            int matchNum = 0;           //  敏感词数量
            String wordTxt = "";        //  检测到的敏感词
            int beginIndex = 100000;    //  文本首部
            int endIndex = 0;           //  文本尾部
            char word;
            Map currMap = keywordMap;
            Map prevMap;
            for(int i = 0; i < txt.length(); i++){
                word = txt.charAt(i);
                if(word >= 'A' && word <= 'Z'){
                    //  大小写字母替代
                    word -= 'A'-'a';
                }else if(ChineseHelper.isTraditionalChinese(word)){
                    //  繁体字替代
                    word = ChineseHelper.convertToSimplifiedChinese(word);
                }
                //  判断该字是否存在于敏感词库中
                prevMap = currMap;
                currMap = (Map) currMap.get(word);
                if(currMap != null){     //  存在
                    if(beginIndex > i){
                        beginIndex = i;
                    }
                    endIndex++;
                    wordTxt += word;
                    //  判断该字是否为结尾字
                    if("1".equals(currMap.get("isEnd"))){
                        if(i != txt.length() - 1 && (Map) currMap.get(txt.charAt(i+1))!=null){    //   最大规则
                            continue;
                        }
                        matchNum++;
                        ansArr.add("Line" + line + ": <" + wordTxt + ">"+txt.substring(beginIndex, beginIndex + endIndex));
                        beginIndex = 100000;
                        endIndex = 0;
                        wordTxt = "";
                        currMap = keywordMap;
                    }
                }else{                 //  不存在
                    if(endIndex > 0 && (word+"").matches("[^(a-zA-Zu4e00-u9fa5)]")){
                        //  过滤伪装字
                        endIndex++;
                        currMap = prevMap;
                    } else{
                        beginIndex = 100000;
                        endIndex = 0;
                        wordTxt = "";
                        currMap = keywordMap;
                    }
                }
            }
            return matchNum;
        }
    

    独到之处有运算量小、检测速度快、便于维护 和几个难题:

    • 敏感词输出怎么查找原词
    • 最小匹配和最大匹配原则有什么区别
    • 拼音替代功能要在什么时候实现(最后选择添加进HashSet中)

    2.计算模块接口部分的性能改进

    记录在改进计算模块性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS 2019、JProfiler或者Jetbrains系列IDE自带的Profiler的性能分析工具自动生成),并展示你程序中消耗最大的函数。


    性能分析图.png
    消耗最大的函数是matches函数,主要是jpinyin使用。一方面,很多功能都依赖于这个函数实现,函数比较累赘,考虑减少其他功能的调用;另一方面,jpinyin下的函数消耗也很大,考虑换一个更优秀的库?

    3.计算模块部分单元测试展示

    展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。

    测试拼音、拼音首字母替代敏感词的添加

    	@Test
        public void testGetPyWord() throws Exception {
    
            //  敏感词
            HashSet<String> keyWordsSet = new HashSet<>();
            keyWordsSet.add("好人");
    
            //  预期答案    共9个
            HashSet<String> ansSet = new HashSet<>();
            ansSet.add("好人");
            ansSet.add("好ren");
            ansSet.add("好r");
            ansSet.add("hao人");
            ansSet.add("h人");
            ansSet.add("haoren");
            ansSet.add("haol");
            ansSet.add("hren");
            ansSet.add("hl");
    
            Tool tool = new Tool();
            tool.getPyWord(0,"好人",keyWordsSet);
            keyWordsSet.equals(ansSet);
        }
    

    4.计算模块部分异常处理说明

    在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。

    IOException
    读写异常:在使用流、文件和目录访问信息时引发的异常

    PinyinException
    拼音异常:发生在无法转换汉字拼音、拼音首字母的场景

    三、心得

    Java语言真的很难啊,相比之下Python简单很多。要是重来一次,我会选择Python,毕竟两种语言都是菜鸟水平。但最后也实现了基本需求,就是单元测试部分还没做得很清楚,IDEA相关的工具用得也很懵,希望下次效率能够提升吧!

  • 相关阅读:
    SGU 176.Flow construction (有上下界的最大流)
    POJ 2391.Ombrophobic Bovines (最大流)
    poj 1087.A Plug for UNIX (最大流)
    poj 1273.PIG (最大流)
    POJ 2112.Optimal Milking (最大流)
    SGU 196.Matrix Multiplication
    SGU 195. New Year Bonus Grant
    关于multicycle path
    ppt做gif动图
    codeforces 598A Tricky Sum
  • 原文地址:https://www.cnblogs.com/dump16/p/15233342.html
Copyright © 2011-2022 走看看