第一次個人編程作業


https://github.com/linzhihuang2000/031902510

一、PSP表格

(2.1)在開始實現程序之前,在附錄提供PSP表格記錄下你估計將在程序的各個模塊的開發上耗費的時間。

(2.2)在你實現完程序之后,在附錄提供的PSP表格記錄下你在程序的各個模塊的開發上實際花費的時間。

PSP2.1 Personal Software Process Stages 預估耗時(分鍾) 實際耗時(分鍾)
Planning 計划
· Estimate · 估計這個任務需要多少時間 60 90
Development 開發
· Analysis · 需求分析 (包括學習新技術) 480 450
· Design Spec · 生成設計文檔 60 90
· Design Review · 設計復審 30 10
· Coding Standard · 代碼規范 (為目前的開發制定合適的規范) 10 20
· Design · 具體設計 60 40
· Coding · 具體編碼 1000 1020
· Code Review · 代碼復審 20 30
· Test · 測試(自我測試,修改代碼,提交修改) 20 60
Reporting 報告
· Test Repor · 測試報告 60 90
· Size Measurement · 計算工作量 10 5
· Postmortem & Process Improvement Plan · 事后總結, 並提出過程改進計划 20 10
· 合計 1830 1915

二、計算機模塊接口

(3.1)計算模塊接口的設計與實現過程。設計包括代碼如何組織,比如會有幾個類,幾個函數,他們之間關系如何,關鍵函數是否需要畫出流程圖?說明你的算法的關鍵(不必列出源代碼),以及獨到之處。(18')

3.1.1類和函數(三個類,15個函數)

  • SensitivewordFilter類:
    • SensitivewordFilter函數,調用SensitiveWordInit類用DFA算法,把敏感詞庫寫入一個Map
    • CheckSensitiveWord2函數:主要實現文本查詢敏感詞的函數
    • Checkstring函數:檢測該純英文+特殊字符的字符串是不是被轉換為拼音的敏感詞
    • initialization函數:因為是一行一行讀入文本,所以每次都要初始化
    • ishan函數:判斷是否為漢字
    • pinyin函數:把敏感詞庫的漢字,轉換為拼音,並用一個Map實現拼音對應漢字
    • hanzitopinyin函數:把該漢字,轉換為拼音
    • splitci()函數:調用splitcihui類的函數,實現漢字左右結構拆分,並用一個Map實現左右結構的兩個漢字對應組成的漢字(弓雖對應強)
    • sum()函數:答案匯總
    • readfile()函數:讀入敏感詞庫
    • readtext()函數:讀入文本
    • outflie函數:輸出文件
  • SensitiveWordInit類:
    • initKeyWord函數:調用addSensitiveWordToHashMap函數
    • addSensitiveWordToHashMap函數:用DFA算法,把敏感詞庫寫入一個Map
  • splitcihui類
    • splitci()函數:把左右結構的漢字記錄起來,存入一個Map中

3.1.2算法關鍵之處:

  • CheckSensitiveWord2函數和Checkstring函數。 基本思想CheckSensitiveWord2函數(遞歸)檢測到一個字符是敏感詞(這里用敏感詞fun舉例,假設文本是fuN),檢測到fu,發現下個N不是n,則把N改為n,再次調用CheckSensitiveWord2函數
    • CheckSensitiveWord2函數:文本一個字符一個字符的讀,若讀到特殊字符:直接讀下一個字符;若是字母:則把它存在一個字符串中,為Checkstring函數作准備; 開始檢測,如果成功,繼續檢測,若失敗,找失敗原因(字母大小寫?還是諧音問題?還是左右結構問題),符合失敗原因,就把當前的字替換一下(例如N替換為n),繼續調用該函數看看能不能成功檢測到敏感詞最后一個字。 若檢測到敏感詞最后一個字,則再次調用該函數,但是檢測的文本要去掉剛剛檢測過的文本

    • Checkstring函數:讀一段只有純英文+特殊字符的字符串,把它轉換為漢字,去檢測敏感詞,看看能否檢測成功。

3.1.3獨到之處

  • 我自認為沒有獨到之處。如果硬要說獨到之處,就是用遞歸的思想,把各種情況實現吧,比如說,文本有F,它可以是用f,法,發.....等等詞匯去檢測

(3.2)計算模塊接口部分的性能改進。記錄在改進計算模塊性能上所花費的時間,描述你改進的思路,並展示一張性能分析圖(由VS 2019、JProfiler或者Jetbrains系列IDE自帶的Profiler的性能分析工具自動生成),並展示你程序中消耗最大的函數。

3.2.1性能改進

  • 剛開始我只是用一個for循環,當檢測不成功的時候(替換一個字符),則i--(把文本下標前移),但是做到一半的時候,我發現這只適用,一個字符只能替換的字只有一種的情況。要是要解決諧音敏感詞時,就不能用了,畢竟諧音對應好幾個(例如:你,尼,擬,泥,妮)。
    • 解決方法:於是乎,我想出了用遞歸的思想,當檢測不成功時,判斷當前的字,是否是被替換的,如果不是,並且他可以替換,就帶着替換的字和當前參數,再次調用這個尋找敏感詞的函數。

3.2.2性能分析圖

  • 可以看出,除了導入拼音包,查找文本中的敏感詞的函數花費的時間最多。代碼如下
 public static int CheckSensitiveWord2(String txt,int j,int n,Map nowMap, String sensitiveci, String nowstring, boolean flag,String ti){
        //從左到右的參數是,文本,文本已經讀到的下標,文本是第幾行,當前敏感詞庫,
        // 當前已經讀到的敏感詞庫中的詞,當前讀到的敏感詞,是否被替換false表示沒有替換
        //當前替換的詞
        String word="";
        int start=-1;//一串純英文加特殊符號在txt的下標
        int end=0;
        for(int i = j; i < txt.length() ; i++) {
            if (!flag)
                word = txt.substring(i, i + 1);
            else
                word=ti;//true表示當前檢測的,是被替換的
            if (regEx.indexOf(word) != -1) {//特殊字符直接跳過
                if (!nowstring.equals(""))
                    nowstring += word;//nowstring不為空,說明當前已找到敏感詞的部分內容
                continue;
            }

            if(!flag)
            {
                if(moderncase.indexOf(word)!=-1)//是不是字母
                {
                    if(string.equals("")) {
                        start = i;
                        tempstringMap=nowMap;
                        tempstringnowstring=nowstring;
                        tempstringsensitiveci=sensitiveci; //把當前參數存起來,為找 變成拼音 的敏感詞
                    }
                    string+=word;
                }
                //當檢測到漢字或是最后一個字符,string(一串純英文)去檢測拼音敏感詞
                if((ishan(word)||i==txt.length()-1)&&!string.equals("")&&start!=-1)
                {
                    if(i==txt.length()-1&&moderncase.indexOf(word)!=-1)
                        end=i;
                    else
                        end=i-1;
                    if(Checkstring(txt,start,end,n)==1)//檢測拼音敏感詞
                    {
                        //返回值為1,說明這串英語字符,是拼音敏感詞
                        nowMap=tempstringMap;
                        nowstring=tempstringnowstring+txt.substring(start,end+1);
                        sensitiveci=tempstringsensitiveci;
                    }
                    string="";
                }
            }
            Map tempMap = nowMap;
            nowMap = (Map) nowMap.get(word);//獲取指定key
            if (nowMap != null) {//存在,則判斷是否為最后一個
                if (!flag)
                    nowstring += word;
                sensitiveci += word;
                flag = false;
                if ("1".equals(nowMap.get("isEnd"))) {//如果為最后一個匹配規則,結束循環,返回匹配標識數
                    total++;
                    an += "Line" + n + ":" + " <" + sensitiveci + "> " + nowstring + "\n";
                    //初始化
                    nowMap = sensitiveWordMap;
                    sensitiveci="";
                    nowstring="";
                    string="";
                    flag=false;
                    ti="";
                    //找完找下一個
                    CheckSensitiveWord2(txt,i+1,n,nowMap,sensitiveci,nowstring,flag,ti);
                    return 1;
                }
            }
            //該字符是英文,但是檢測不成功
            else if(moderncase.indexOf(word)!=-1&&!flag)
            {
                int pan=2;
                String tempstring=nowstring;
                if(uppercase.indexOf(word)!=-1)//是小寫
                {
                    flag = true;
                    nowstring += word;
                    word = word.toLowerCase();//改為大寫再次檢測
                    ti=word;
                    nowMap = tempMap;
                    pan=CheckSensitiveWord2(txt,i,n,nowMap,sensitiveci,nowstring,flag,ti);
                }
                else//大寫的話,改為小寫去檢測
                {
                    flag = true;
                    nowstring += word;
                    word = word.toUpperCase();
                    ti=word;
                    nowMap = tempMap;
                    pan=CheckSensitiveWord2(txt,i,n,nowMap,sensitiveci,nowstring,flag,ti);
                }
                if(pan==1) {//pan為1,說明被替換的字母正是我們要找的
                    string = "";
                    return 1;
                }
                //否則,就初始化
                    sensitiveci = "";
                    nowstring = "";
                    nowMap = sensitiveWordMap;
                    flag = false;
            }
            //字符是漢字,但是檢測不成功,可能是諧音,或者左右結構拆開的原因(強=弓雖)
            else if(ishan(word) && !flag)
            {
                int pan=2;//用來判斷的
                String word2;
                if (i != txt.length() - 1)//左右結構拆開
                {
                    word2 = txt.substring(i + 1, i + 2);
                    if (ishan(word2)) {
                    String word3 = word;
                    word3 += word2;
                    if (split.containsKey(word3)) {//如果改字是被拆開的,那把他組合起來再去檢測
                        flag = true;
                        nowstring += word3;
                        word = split.get(word3);
                        nowMap = tempMap;
                        pan=CheckSensitiveWord2(txt,i+1,n,nowMap,sensitiveci,nowstring,flag,word);
                    }
                    if(pan==1)//pan為1,說明組合起來的字去檢測是成功的
                    return 1;
                   }
                }
                //諧音問題
                String wordpinyin=hanzitopinyin(word);//把該字轉換為拼音
                if(pinyintohanzi.containsKey(wordpinyin))//如果該拼音的確是敏感詞
                {
                    String temp=pinyintohanzi.get(wordpinyin);//一串是諧音的敏感詞字符串,例如(fa),該字符串就是發法罰....
                    flag = true;
                    nowstring += word;
                    nowMap = tempMap;
                        for (int z=0;z<temp.length();z++)//一個一個諧音去試
                        {
                            word=temp.substring(z,z+1);
                            pan=CheckSensitiveWord2(txt,i,n,nowMap,sensitiveci,nowstring,flag,word);
                            if(pan==1)
                                return 1;
                        }
                }
                sensitiveci = "";
                nowstring = "";
                nowMap = sensitiveWordMap;
                flag = false;
            }
            //該字符不能被替換,或已經被替換過了
            else {
                if(flag)
                    return -1;//-1表示替換了,也不成功
                sensitiveci = "";
                nowstring = "";
                nowMap = sensitiveWordMap;
                flag = false;
            }
        }
        return 2;//2表示程序正常結束
    }

(3.3)計算模塊部分單元測試展示。展示出項目部分單元測試代碼,並說明測試的函數,構造測試數據的思路。並將單元測試得到的測試覆蓋率截圖,發表在博客中。(12')

- 1.測試能否用DFA方法建立樹

 public static void main(String[] args) {
        long beginTime = System.currentTimeMillis();
        Set<String> set1 = new HashSet<String>();
        splitci();
        set1 = readfile("D:\\testwords.txt");//讀入敏感詞文件
        SensitivewordFilter filter = new SensitivewordFilter(set1);//把敏感詞用DFA寫入Map
        long endTime = System.currentTimeMillis();
        System.out.println("總共消耗時間為:" + (endTime - beginTime)+"毫秒");
    }
  • testword.txt文件包含(笨蛋和笨逼)兩個敏感詞結果如下
  • 測試覆蓋率如下

- 2.測試檢測文本中的敏感詞匯,測試思路:判定為敏感詞的要求(中文:插字符,諧音,拼音,拼音首字母,左右結構。英語:插字符,大小寫)

  public static void main(String[] args) {
        long beginTime = System.currentTimeMillis();
        Set<String> set1 = new HashSet<String>();
        splitci();
        set1 = readfile("D:\\testwords.txt");//讀入敏感詞文件
        SensitivewordFilter filter = new SensitivewordFilter(set1);//把敏感詞用DFA寫入Map
        readtext("D:\\testorg.txt");
        sum();//把答案匯總;
        outflie("D:\\testans.txt");//輸出文件
        long endTime = System.currentTimeMillis();
        System.out.println("總共消耗時間為:" + (endTime - beginTime)+"毫秒");
    }
  • 敏感詞(hello,山寨,愛過,強奸)和檢測文本

  • 結果如下

  • 測試覆蓋率如下

(3.4)計算模塊部分異常處理說明。在博客中詳細介紹每種異常的設計目標。每種異常都要選擇一個單元測試樣例發布在博客中,並指明錯誤對應的場景。(6')

IOError: 當輸入文件不存在,輸出找不到該文件

  • 單元測試代碼:
    public static void readfile(String readf) {
        try {
            File f = new File(readf);//指定文件
            FileInputStream fis = new FileInputStream(f);//創建輸入流fis並以f為參數
            InputStreamReader isr = new InputStreamReader(fis,"UTF-8");//創建字符輸入流對象isr並以fis為參數
            BufferedReader br = new BufferedReader(isr);//創建一個帶緩沖的輸入流對象br,並以isr為參數
        } catch (Exception e) {
            System.out.println("找不到該文件");
            e.printStackTrace();
        }
    }
  • 沒有文件的情況:

三、心得

(4.1)在完成本次作業過程的心得體會。

  • 通過本次學習,我發現了自己有很多的不足之處,從頭到尾都在學習與借鑒,從最基本的java如何輸入輸出文件,到那些JProfile性能分析工具怎么安裝使用。基本上無時無刻在學習,深深地感覺到了自己的不足。
  • 也當然學會了很多知識,邊寫代碼邊找到bug,讓我學會了很多解決方法。也了解了如何使用一些工具等等。
  • 最最重要的是,當前還是無法完全解決拼音帶來的問題,在很多情況下還是檢測不出來。平心而論,已經盡力了,但能力有限,只能今后加倍提升自己。如果有解決的方法或者本人代碼不足之處,歡迎留言告知。
  • 再補充一點,看到大佬們提交的作業,也發現了應該用,各種情況的笛卡爾積去建樹(DFA),但截止時間將至,只好有空的時候對大佬們提交的作業進行學習借鑒。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM