天天看點

第一次個人程式設計作業

GitHub連結

一、PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃
· Estimate · 估計這個任務需要多少時間 10 20
Development 開發
· Analysis · 需求分析 (包括學習新技術) 120
· Design Spec · 生成設計文檔 30
· Design Review · 設計複審 5
· Coding Standard · 代碼規範 (為目前的開發制定合适的規範)
· Design · 具體設計 180 300
· Coding · 具體編碼 900 1200
· Code Review · 代碼複審 600
· Test · 測試(自我測試,修改代碼,送出修改)
Reporting 報告
· Test Repor · 測試報告
· Size Measurement · 計算工作量
· Postmortem & Process Improvement Plan · 事後總結, 并提出過程改進計劃
· 合計 1585 2475

二、計算子產品接口

2.1 計算子產品接口的設計與實作過程

2.1.1 程式設計思路

  • 在剛開始看到這個題時我隻能想到循環查找字元串、利用樹存儲來加快時間等模糊的想法,但并沒有實際的能力去實作。在我參考了不少同學的思路後,我發現總共大多是使用DFA或AC自動機的方法。在思考哪個更适合我之後,我選擇了用python來實作DFA算法。
    第一次個人程式設計作業
    如圖将關鍵詞“你真帥”“我真好”“你真牛”用該樹存儲起來。從根節點開始,在比較待查文本的字元時,若遇到“你”則進入“你”節點,并判斷此時狀态:顯然并不是終點,“帥”或“牛”才是。而如果整個比較過程都沒有出錯,順利到了終點,那麼便成功找到了一個關鍵詞,若出錯則重來。
  • 在python中,用字典dict來實作DFA算法較友善。如下,可見使用字典實作可以避免不少麻煩。
state_event_dict = {
        '你':{
            '真':{
                '帥':{
                    'is_end':True
                },'is_end':False
                '牛':{
                    'is_end':True
                },'is_end':False
            },
        },
        '我':{
            '真':{
                '好':{
                    'is_end':True
                },'is_end':False
            },'is_end':False
        }
    },

           

2.1.2代碼實作

    • class DFA

      内含

      _generate_state_event_dict

      函數,自動生成keyword_list(關鍵詞查找樹),以及

      match

      函數,根據輸入的關鍵詞在(keyword_list)樹上查找并輸出。但隻提供了基礎的輸入輸出功能,對關鍵詞輸入的優化(增添删改)以及擷取資料的輸出格式還需外部函數進行優化。
  • 主要函數

    • 将敏感詞從檔案輸入并轉為清單友善操作
    • def read_keywords(file_path):
          with open(file_path, encoding='utf-8') as keyword_list:
              return keyword_list.read().splitlines()
                 
      将待查文本從檔案輸入轉為字元串友善操作
    • def read_article(file_path):
          with open(file_path, encoding='utf-8') as article:
              return article.read()
                 
      将資料按格式輸出到ans.txt
    • def write_ans(file_path, ans_list):
      with open(file_path, 'w', encoding='utf-8') as ans:
          ans.write('total: '+str(ans_list[0])+'\n')
          for word in ans_list:
              if isinstance(word, int):
                  continue
              ans.write('line'+str(word['line'])+': '+'<'+real_keyword[word['keyword']]+'> ' + word['match'] + '\n')
                 
      處理敏感字清單,加入拼音、拼音首字母、漢字、偏旁部首等各種變形的敏感字plus
      def word_handle(keyword_list):
        after_list = []
        # 小寫
        for keyword in keyword_list:
            after_list.append(keyword.lower())
        # 轉拼音
        for keyword in keyword_list:
            # 注意使用lazy_pinyin(一維清單)而不是pinyin(二維清單)
            # after_list.append("".join(lazy_pinyin(keyword)))
            pinyin_list = lazy_pinyin(keyword)
            # 首字母
            first_letter_list = lazy_pinyin(keyword, 4)
            # 判斷是否中文避免數組越界(
            if ord(keyword[0]) > 255:
                dfs(after_list, pinyin_list, first_letter_list, "", 0, len(keyword))
        return after_list
                 
    • 關鍵的遞歸,讓敏感字變形更迅速,擴充敏感字清單也就更友善
      def dfs(after_list, pinyin_list, first_letter_list, cur_chars, w, length):
      if w == length:
          after_list.append(cur_chars)
          return
      dfs(after_list, pinyin_list, first_letter_list, cur_chars + first_letter_list[w], w + 1, length)
      dfs(after_list, pinyin_list, first_letter_list, cur_chars + pinyin_list[w], w + 1, length)
      
                 

2.2 計算子產品接口部分的性能改進

  • 由于pycharm是社群版沒有profiler,于是隻好用了自帶的cprofile,由圖可見第三方庫的引用占了不少的時間
    第一次個人程式設計作業

2.3 計算子產品部分單元測試展示

敏感詞1

第一次個人程式設計作業

待查文本1

第一次個人程式設計作業

答案1

第一次個人程式設計作業

2.4 計算子產品部分異常處理說明

三、心得

  • 在寫代碼前一定要預留出足夠的時間去思考需要完成什麼、需要學什麼、怎麼調試,并且題目一定一定一定要看清楚,不然可能會出現急頭白臉看了一堆資料、寫了一堆東西結果沒用的情況。
  • 而本次實驗對我來說比較難,參考了好多教程、代碼,用了好多不同的方式才勉強出來一部分。但是即便花了不少精力,還是沒能來得及,反思了下,原因應該是沒有客觀合理地預料這一周需要完成的各種事務,以至于沒能預留出足夠的時間在這個項目上,導緻哪怕快通宵了還是沒能完成。不過這才是第一次,希望吸取了經驗教訓後将來能有所進步。