第一次个人编程作业

https://github.com/xiao-qingjiang/SE2021

一、PSP表格

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

二、计算模块接口

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

  • 拼音拆字简繁体转换调用了现有的python库

  • 使用了(DFAfliter) 类来实现解析传入敏感词文件路径添加敏感词识别文本中的敏感词等功能,其中包括了以下五个函数:

    • __init__(self):定义实例化该类所需的一些变量
    • add_keyword(self, chars, level) :将一个敏感词添加到敏感词库中,由于需要被后续add函数多次调用,因此单独封装方便使用
    • add(self, chars, level):将敏感词的各种变形类型分析讨论,并分别调用上述add_keyword函数将各种敏感词变体(变体方式会在下文分享)存入敏感词库
    • filter(self, message):对传入的文本内容进行检测过滤敏感词,并转化为所要求的输出格式,然后把转化结果添加到列表
    • parse(self, path)解析文件路径读入敏感词文件,并调用add函数敏感词添加到敏感词库
  • 类外函数:

    • chai_zi(keywords, dfa_instance):将所有敏感词传入,并将每个敏感词进行拆字,再添加到敏感词库中
    • read_file(file_path):读入测试文本文件,并将文本中每一行分别存入同一个列表
    • output(filename):将filter函数中形成的结果列表输出到指定输出文件
    • type_nums(depth, queue, lens):使用DFS算法将每一个敏感词可能的组合变形方式枚举
  • 算法流程:

  • 独到之处:

    算法的难点主要还是敏感词库的建立,如何把敏感词库建得全面、并且在全面的同时尽量避免冗余,这是一项挑战,我使用了DFS算法进行枚举,并使用Tire树构建敏感词库。以下为主要难点及解决方案

    • 排列组合形成变体:假设“浑轮“是一个敏感词(因为这两个字都有繁体字,方便举例说明)”暂用“浑轮”一词来进行描述。其中”浑轮“这两个字每个字都有拼音拆字繁体简体首字母替代五种表示形式,则”浑轮“一词就有5*5种表示形式(此处说明省略在中间插入特殊字符的情况,因为这种情况可统一避免),上述”浑轮“是两个字,组合形式有(5^2)种,如果敏感词是n个字,就是(5^n)​​​种,因此我使用了DFS来进行搜索,以”浑轮“为例,假设我分别用0,1,2,3,4表示拼音、拆字、繁体、简体、首字母替代五种表示形式,则[0, 1]表示”浑“字用拼音表示,”轮“字用拆字表示,以此类推,可将所有组合方式枚举出并存到敏感词库中

    • Tire树构建敏感词库

    • 拼音化与首字母替代:使用python库pypinyin实现

    • 拆字:使用python库pychai实现

    • 繁体-简体转化:使用python库zhconv实现

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

性能分析图:

  • 从上图可以看出,函数执行的大部分时间,都是由拆字操作带来的,其中经过测试,我发现是初始化调用用于拆字的pychai库时占用了绝大部分时间,因此,我选择了尽可能减少调用次数,到最后全程只调用了一次这个函数,大大减少了时间消耗
  • 在写代码过程中,其实在存储敏感词库时不同的方法也是具有着很大的性能差异,我通过结合DFS算法来调整DFA算法避免了相同形式的敏感词重复存入的情况,减小了冗余提高了性能

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

部分单元测试:

  • 测试拆字功能
      import unittest
      import main
      class Test(unittest.TestCase):
          """用于测试say_hello_function.py"""

          def test_chai_zi(self):
              """测试能否正确拆字"""
              dfa = main.DFAFilter()
              res = main.chai_zi("好", dfa)
              self.assertEqual(res, "女子")

      if __name__ == '__main__':
          unittest.main()

  • 测试读入文件功能
      import unittest
      import main

      class Test(unittest.TestCase):
          """用于测试say_hello_function.py"""

          def test_read_file(self):
              """测试能否正确拆字"""
              res = main.read_file(r"org.txt")
              self.assertEqual(res[0], "你好,好久不见")

      if __name__ == '__main__':
          unittest.main()

  • 覆盖率截图

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

  • 命令行输入异常
    • 如果输入四个文件,则按顺序传入
    • 如果只输入可执行python文件,使用默认路径执行
    • 其他情况,输出提示并正常退出
      if len(sys.argv) == 4:
          words_txt = sys.argv[1]
          org_txt = sys.argv[2]
          ans_txt = sys.argv[3]
      elif len(sys.argv) == 1:
          words_txt = "words.txt"
          org_txt = "org.txt"
          ans_txt = "ans.txt"
      else:
          print("请正确输入:python main.py 文件路径 文件路径 文件路径")
          exit(0)
  • 当少输入了一个参数
      python main.py words.txt org.txt

则输出文字提示并正常退出

      请按正确格式输入:python main.py 文件名 文件名 文件名

三、心得

  • 真正尝试了比较接近工程的作业,这个作业也很具备实际意义,做起来动力十足(虽然做得不怎么样), 完成这次作业是一个不断学习的过程,但好在能够明确需要学什么,感觉这次作业对能力的提升是很有帮助的
  • 不要重复造轮子,第一次体会到了这句话(虽然我也不会造哈哈,目前只会用)。这次作业可以说是面向github编程,比如在解决拼音、简繁体转化、拆字时,都在网上找到了python的包,对完成作业起了很大的作用。
  • 但有点可惜的是这次由于时间规划不合理,后期优化约等于0,在首字母替代的处理上也有点bug,目前已经发现了bug,但现在改显然已经来不及了,以后可能要更好地提前做好规划
  • 自从数据结构与算法课结束后,就很久没有打代码了,这次写代码很生疏,希望这个能在之后的练习中得到改善
  • 果然实践是最好的老师,这次算是第一次真正的用python写代码,以前有大概了解过python的基本语法,但完全没有写过,要不是这次C++没有合适的包把我给劝退了,还真不敢用python上,但没办法呀,不用python的话,C++又不会拆字,也不会简繁体转化,作业都做不了,只能硬着头皮上,不过还好,边写边查,最后也算是写出来了
原文地址:https://www.cnblogs.com/xiao-qingjiang/p/15294221.html