天天看点

第一次个人编程作业

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 计算模块部分异常处理说明

三、心得

  • 在写代码前一定要预留出足够的时间去思考需要完成什么、需要学什么、怎么调试,并且题目一定一定一定要看清楚,不然可能会出现急头白脸看了一堆资料、写了一堆东西结果没用的情况。
  • 而本次实验对我来说比较难,参考了好多教程、代码,用了好多不同的方式才勉强出来一部分。但是即便花了不少精力,还是没能来得及,反思了下,原因应该是没有客观合理地预料这一周需要完成的各种事务,以至于没能预留出足够的时间在这个项目上,导致哪怕快通宵了还是没能完成。不过这才是第一次,希望吸取了经验教训后将来能有所进步。