Fork me on GitHub

第一次个人编程作业

https://github.com/fzu-TJT/SEwork1/tree/master

一、PSP表格

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

二、计算模块接口

  • (3.1)计算模块接口的设计与实现过程。

    思路: 刚开始看到的时候是没有什么思路的。然后就只好靠baidu编程了。找了些资料后大体有两种比较高效的方法:第一种是DFA算法,第二种是AC自动机。我选择的是第一种方法,DFA算法。

    DFA算法:DFA即Deterministic Finite Automaton,也就是确定有穷自动机,它是是通过event和当前的state得到下一个state,即event+state=nextstate。我们可以将每个敏感词汇作为状态,例如“讨厌鬼”可拆分为“讨”、“讨厌”、“讨厌鬼” 三个文本片段。如果是多段关键词,则如“匹配算法”、“匹配关键词”以及“信息抽取”。如下图类似树形结构,也正是因为这个结构,使得DFA算法在关键词匹配方面要快于关键词迭代方法(for 循环)。

parse(树状化)::构建一个敏感词字典树

view code
def parse(self, path):
    with open(path, encoding='UTF-8') as f:
        
        for keyword in f:
            keyword=keyword.replace("\n", "")
            if isChinese(keyword):
                pinyin_list.append(pinyin.get(keyword, format='strip', delimiter=""))
                haha_pattern=""
                for ch in keyword:
                    haha_pattern=haha_pattern+ch
                    haha_pattern+='.{0,20}'
                re_pattern_list.append(haha_pattern[:-7])
                total_list.append(keyword)
                
                
                tt_word=keyword
                for tt_cha in tt_word:
                    ttt_word=keyword
                    #print(pinyin.get(tt_cha, format='strip', delimiter=""))
                    ttt_word=ttt_word.replace(tt_cha, pinyin.get(tt_cha, format='strip', delimiter=""))
                    #print(ttt_word)
                    self.add(ttt_word)
                    haha_pattern=""
                    for ch in ttt_word:
                        haha_pattern=haha_pattern+ch
                        haha_pattern+='.{0,20}'
                    re_pattern_list.append(haha_pattern[:-7])
                    #print(haha_pattern[:-7])
                    total_list.append(keyword)
                
                
            else:
                hh_pattern=""
                for ch in keyword:
                    hh_pattern=hh_pattern+ch
                    hh_pattern+='.{0,20}'
                re_pattern_list.append(hh_pattern[:-7])
                English_word_list.append(keyword)
                total_list.append(keyword) 
            self.add(keyword.strip())
        for temp_word in pinyin_list:
            self.add(temp_word.strip())
            hh_pattern=""
            for ch in temp_word:
                hh_pattern=hh_pattern+ch
                hh_pattern+='.{0,20}'
            re_pattern_list.append(hh_pattern[:-7])
            total_list.append(keyword)
    #print(self.keyword_chains)

filter(过滤原文):并完成答案的生成等

view code
   def filter(self, message, repl="*"):
    if not isinstance(message, str):
        message = message.decode('utf-8')
    back = message
    message = message.lower()
    for i in range(len(re_pattern_list)):
        message=re.sub(re_pattern_list[i], total_list[i], message)
    ret = []
    start = 0
    fd=open("anss.txt", "a")
    tmp_char=""
    while start < len(message):
        level = self.keyword_chains
        step_ins = 0
        for char in message[start:]:
            if char in level:
                step_ins += 1
                if self.delimit not in level[char]:
                    level = level[char]
                else:
                    count_num = start
                    while(1):
                        if back[count_num] == message[start + step_ins]:
                            break
                        tmp_char=tmp_char+back[count_num]
                        count_num += 1
                    ret.append(repl * step_ins)
                    print("Line", end="")
                    print(index, end="")#行号 index表示第几行
                    print("<", end="")
                    print(message[start:start+step_ins], end="")#敏感词
                    print(">")
                    print(tmp_char)
                    # fd.write("Line")
                    # fd.write(str(index))
                    # fd.write("<")
                    # fd.write(message[start:start+step_ins])
                    # fd.write(">\n")
                    temp_str="Line"+str(index)+"<"+message[start:start+step_ins]+"> "+tmp_char+"\n"
                    tmp_char=""
                    
                    #print(temp_line[start:start+step_ins])#在文中的表述
                    SUM_LIST.append(temp_str)
                    start += step_ins - 1
                    break
            else:
                ret.append(message[start])
                tmp_char = ""
                break
        else:
            ret.append(message[start])
        start += 1
    fd.close()

    return ''.join(ret)

  • (3.2)计算模块接口部分的性能改进。

通过Spyder下载的profile工具测试得到下图

得到耗时最大的函数是DFAFilter类的filter


    def filter(self, message, repl="*"):
        if not isinstance(message, str):
            message = message.decode('utf-8')
        message = message.lower()
        for i in range(len(re_pattern_list)):
            message=re.sub(re_pattern_list[i], total_list[i], message)
        ret = []
        start = 0
        fd=open("MyAnswer.txt", "a")
        while start < len(message):
            level = self.keyword_chains
            step_ins = 0
            for char in message[start:]:
                if char in level:
                    step_ins += 1
                    if self.delimit not in level[char]:
                        level = level[char]
                        
                    else:
                        ret.append(repl * step_ins)
                        print("Line", end="")
                        print(index, end="")#行号 index表示第几行
                        print("<", end="")
                        print(message[start:start+step_ins], end="")#敏感词
                        print(">")
                        # fd.write("Line")
                        # fd.write(str(index))
                        # fd.write("<")
                        # fd.write(message[start:start+step_ins])
                        # fd.write(">\n")
                        temp_str="Line"+str(index)+"<"+message[start:start+step_ins]+">\n"
                        
                        #print(temp_line[start:start+step_ins])#在文中的表述
                        SUM_LIST.append(temp_str)
                        start += step_ins - 1
                        break
                else:
                    ret.append(message[start])
                    break
            else:
                ret.append(message[start])
            start += 1
        fd.close()

        return ''.join(ret)

对于改进方法的话,鉴于本人水平有限,尚在努力寻找方法,有方法一定会更新的。

  • (3.3)计算模块部分单元测试展示。

单元测试代码如下。

view code
import main
import unittest

class MyTestCase(unittest.TestCase):
  def test_FilterSensitiveWords(self):
    #构造数据
    path = "words1.txt"
    f.ReadSensitiveWords(path)
    answer = []
    for i in range(1,7):
        sen_count,answer = f.FilterSensitiveWords(i,org[i-1],answer)
    self.assertEqual(ans,answer)

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

自己构造测试文本截图如下:

测试文本截图如下:

  • (3.4)计算模块部分异常处理说明。

异常处理说明目前考虑到的只有关于I/O错误的情况,具体代码如下。

if len(sys.argv) != 4:
    print("I/O error")

三、心得

  • (4.1)在完成本次作业过程的心得体会

学了好多东西,刚开始的时候啥也不会,心态炸裂。一步一步查资料,一步一步改进。重新温顾了GitHub传代码的方法,学习了dfa算法等等。本次作业我也学到了很多我以前没有用过的东西,比如性能分析、单元检测等以前没有用过的东西,但是遗憾的是还是有一点小问题没有改进,会持续改进。

posted @ 2021-09-16 22:37  TJThunder  阅读(39)  评论(0编辑  收藏  举报