软工作业 5:词频统计——增强功能
2018-12-02 20:43 潘博 阅读(165) 评论(1) 编辑 收藏 举报一、基本信息
1.1 编译环境、项目名称、作者
1 #编译环境:python3.6
2 #项目名称:软工作业5-词频统计—增强功能
3 #作者:1613072055 潘博
4 # 1613072056 侯磊
1.2项目地址
- 本次作业地址: https://www.cnblogs.com/panboo/
- 项目git地址: https://gitee.com/ntucs/PairProg/tree/SE055_056
二、项目分析
-
程序运行模块(方法、函数)介绍
Task 1. 接口封装 —— 将基本功能封装成(类或独立模块)
将基本功能:统计文本总词数,统计文本最多的十个单词及其词频这两个方法封装在类Core中,使用面向对象的思想将两个基本功能解耦合,
使之成为通用的方法。
1 # encoding = utf-8 2 import re 3 4 class Core: 5 def process_file(dst): # 读文件到缓冲区 6 try: # 打开文件 7 file1 = open(dst, "r") 8 except IOError as s: 9 print(s) 10 return None 11 try: # 读文件到缓冲区 12 bvffer = file1.read() 13 except: 14 print("Read File Error!") 15 return None 16 file1.close() 17 return bvffer 18 19 def word_count(self, bvffer): 20 #bvffer = self.process_file(dst) # 调用方法读数据到缓存区 21 try: 22 count = 0 23 # 统计行数 24 for i in bvffer: # 统计文件内容中换行符的数目 25 if i == '\n': 26 count += 1 27 return count 28 except: 29 print("Read File Error!") 30 31 def word_freq_t10(self, bvffer): 32 #bvffer = self.process_file(dst) # 调用方法读数据到缓存区 33 stop = open("stopwords.txt", 'r', encoding='UTF-8') # 停词表的读取 34 stop_file = stop.read() 35 stop_words = stop_file.replace('\n', " ").lower().split() 36 for i in bvffer: # 去除特殊字符 37 if i in '!"#$%&()*+-,-./:;<=>?@“”[\\]^_{|}~': 38 bvffer = bvffer.replace(i, " ") # 替换特殊字符 39 words = bvffer.lower().split() 40 if words: 41 Newwords = [] 42 words_select = '[a-z]{4}(\w)*' # 用正则表达式筛选合格单词 43 for i in range(len(words)): 44 word = re.match(words_select, words[i]) 45 if word: 46 Newwords.append(word.group()) 47 # 统计单词的词频 48 word_freq = {} # 定义字典而非数组 49 for word in Newwords: 50 word_freq[word] = word_freq.get(word, 0) + 1 51 sorted_word_freq = sorted(word_freq.items(), key=lambda v: v[1], reverse=True) # 对合格单词词频排序 52 return sorted_word_freq[:10] # 返回排序数组的前十个元素
编写一个test5.py,通过import WordCount5模块,可以在cmd命令行中测试上述的封装类,也可以直接在Pycharm开发环境中测试。
1 from SE_fifthwork_task1 import WordCount5 2 import argparse 3 if __name__ == '__main__': 4 parser = argparse.ArgumentParser(description="your script description") # description参数可以用于插入描述脚本用途的信息,可以为空 5 parser.add_argument('--f', '-f', type=str, default='Gone_with_the_wind.txt', help="读取文件路径") 6 args = parser.parse_args() # 将变量以标签-值的字典形式存入args字典 7 dst = args.f 8 print(dst) 9 core = WordCount5.Core() 10 bvffer = WordCount5.Core.process_file(dst) 11 12 # 任务一 第一个要求测试 13 count = WordCount5.Core.word_count(core, bvffer) 14 print(count) 15 16 # 任务一: 第二个要求测试 17 # sorted_word_freq = WordCount5.Core.word_freq_t10(core, bvffer) 18 # for item in sorted_word_freq: # 输出 Top 10 的单词 19 # print("<%s>:%d " % (item[0], item[1]))
对任务1的两个基本方法测试所得结果截图如下:
Task 2. 增加新功能
- 词组统计:能统计文件夹中指定长度的词组的词频
- 自定义输出:能输出用户指定的前n多的单词与其数量
封装类Core的代码:
1 # encoding = utf-8 2 import re 3 4 5 class Core: 6 def __init__(self, dst, m, n, o): # dst:文件路径;m:词组长度;n:输出的单词数量 7 self.dst = dst 8 self.m = m 9 self.n = n 10 self.o = o 11 12 def process_file(self): # 读取文件 13 try: # 打开文件 14 file1 = open(self.dst, "r", encoding='GBK') 15 except IOError as s: 16 print(s) 17 return None 18 try: # 读文件到缓冲区 19 bvffer = file1.read() 20 except: 21 print("Read File Error!") 22 return None 23 file1.close() 24 return bvffer 25 26 def process_buffer(self, bvffer): 27 if bvffer: 28 chara_num = 0 29 blank = '' 30 for chara in bvffer: # 统计字母的数目 31 if chara.isalpha(): 32 chara_num += 1 33 count = 0 34 for i in bvffer: # 统计文件内容中换行符的数目 35 if i == '\n': 36 count += 1 37 if i[-1] != '\n': # 当文件最后一个字符不为换行符时,行数+1 38 count += 1 39 for ch in ':,.-_': 40 bvffer = bvffer.lower().replace(ch, " ") 41 fwords = bvffer.strip().split() 42 43 for i in range(self.m): 44 blank += '[a-z]+' 45 if i < self.m - 1: 46 blank += '\s' 47 last = re.findall(blank, bvffer) # 正则查找词组 48 word_freq = {} 49 for word in last: # 将正则匹配的结果进行统计 50 word_freq[word] = word_freq.get(word, 0) + 1 51 return word_freq, chara_num, len(fwords), count 52 53 def output_result(self, word_freq): 54 if word_freq: 55 sorted_word_freq = sorted(word_freq.items(), key=lambda v: v[1], reverse=True) 56 for item in sorted_word_freq[:self.n]: # 输出 Top n 的单词 57 print("<%s>:%d " % (item[0], item[1])) 58 return sorted_word_freq[:self.n] 59 60 def print_result(self): 61 print('读入的文件路径为:' + str(self.dst)) 62 print('统计词组长度为:' + str(self.m)) 63 print('输出的单词数量为:' + str(self.n)) 64 print('文件的存储路径为:' + str(self.o)) 65 buffer = Core.process_file(self) 66 word_freq, characters, count_words, count = Core.process_buffer(self, buffer) 67 print("characters:%d " % characters) 68 print("lines:%d " % count) 69 print("words:%d " % count_words) 70 items = Core.output_result(self, word_freq) 71 f = open(self.o, 'w+') 72 print("characters:%d " % characters, file=f) 73 print("lines:%d " % count, file=f) 74 print("words:%d " % count_words, file=f) 75 for item in items: # 格式化 76 item = '<' + str(item[0]) + '>:' + str(item[1]) + '\n' 77 f.write(item) 78 f.close() 79 80 81 if __name__ == '__main__': 82 test = Core('Gone_with_the_wind.txt', 3, 5, 'main.txt') 83 test.print_result()
import argparse模块进行命令行传参测试代码:
1 # encoding = utf-8 2 import WordCount5 3 import argparse 4 5 6 if __name__ == '__main__': 7 parser = argparse.ArgumentParser(description="your script description") # description参数可以用于插入描述脚本用途的信息,可以为空 8 parser.add_argument('--i', '-i', type=str, default='Gone_with_the_wind.txt', help="读取的文件路径") 9 parser.add_argument('--m', '-m', type=int, default=2, help="词组包含单词数量") 10 parser.add_argument('--n', '-n', type=int, default=5, help="输出的词组数量") 11 parser.add_argument('--o', '-o', type=str, default='result.txt', help="存储文件路径") 12 args = parser.parse_args() # 将变量以标签-值的字典形式存入args字典 13 dst = args.i 14 m = args.m 15 n = args.n 16 o = args.o 17 test5 = WordCount5.Core(dst, m, n, o) 18 test5.print_result()
运行成果图:
①使用 -i 传递参数“读取的文件路径”
①使用 -m 传递参数“词组包含单词数量”
②使用 -n 传递参数 “输出的词组数量”
③使用 -0 传递参数 “存储文件路径”
④-0 -i -m -n 一起使用
三、性能分析
本次实验在作业4基础上进行,在时间、空间复杂度方面差不多,所以运行很流畅。
1.根据执行时间分析
2、性能图表:
四、PSP 表格
五、事后分析与总结
1 在封装Core模块时——讨论过程
在解决封装方式时,我们两位同学在解决方法方面出现了分歧。
55号潘博考虑在设计和实现一个客观系统时,在满足需求的条件下,把系统设计成一些不可变的(相对固定)部分组成的最小集合(最好的设计)。
这些不可变的部分就是所谓的对象。也就是使用面向对象的思想将原来我们写的作业4的项目进行分解成可复用的类方法,从而达到易维护和易扩展的
特点。
56号侯磊同学认为使用面向过程,将所有业务逻辑写在一起,可以减少代码量并且容易实现,相对来说性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
最后,我们综合考虑是作业要求和开发模式优缺点,决定使用潘博同学的方法。
2 互相评价
潘博评价侯磊:侯磊同学虽然在编程方面基础不是很好,但是在合作的过程中积极为项目做贡献,在查阅资料与学习
方面不遗余力。美中不足的是对编写程序背后的逻辑方面,不够严谨,希望以后能够多加思考。
侯磊评价潘博:潘博同学不管在编程能力还是在技术储备方面都非常优秀,能够灵活运用已经学习的各门专业知识,
并且在代码编写与调试方面也非常熟练。在完成任务的同时,积极帮助我解答疑问,受益匪浅,期待下一次的合作。
3 评价整个过程
我们觉得,从本次作业完成的过程中,理解了软件工程不仅仅是一门关于程序编写与设计的学科,他还是一门包含“人”
的学科,甚至团队合作是软件开发中的至关重要的一环。
4.结对编程照片
5.其他
经过这两次的合作编程,我们双方的编程能力都有提高。在合作的过程中,我们互相学习、帮助,一起解决问题,这两次的合作对我们非常有意义。