20180918-1 词频统计

作业要求参见 https://edu.cnblogs.com/campus/nenu/2018fall/homework/2126
 
一、项目功能的重点、难点  及执行效果
 
1.功能一中的重点和难点
 
(1).文件读取 
       功能要求从文件中读取数据信息,那么首先要处理的就是数据读入问题,项目采用Python语言编码(以下如果无特殊说明,所用方法均基于Python),Python对于文件读入有非常实用的方法:open(filename,mode,buffering,encoding)方法,其中filename为文件全称,mode为文件的读取模式,buffering为j寄存区的缓冲大小,encoding为文件的编码方式,代码如下:
1  f = open(str,'r',-1,'utf-8')        #str为待输入文件名,'r'代表只读模式,'-1'为默认缓冲区大小
 (2).分词依据 
        统计词频,首先要做的就是区分什么是一个单词,也是本功能甚至本项目中的一个重点和难点。第一,单词是不 包括标点符号的;第二,本作业的要求是word中对单词的定义,根据个人的观察和试验,得出结论,word中的分词依据主要是空格、英文破折号(—)、和双短横线(--)。根据这两点分析,对于分词功能,主要采取的方法是首先将所有字符小写,用到的是Python中字符串的lower()方法,然后将文档中的标点符号和换行符使用空格进行替换,替换之后每个单词之间都是由空格相隔开,然后使用字符串处理的split()方法将所有的单词保存于列表(list)中,代码如下:
1 tet = f.read().lower()                                               #读取文本内容并将字母全部转换为小写形式
2 
3 text = tet.replace('\n',' ').replace('.',' ').replace(',',' ').\      #对标点符号的替换操作
4    replace('!',' ').replace('\\',' ').replace('#',' ').\
5    replace('[',' ').replace(']',' ').replace(':',' ').\
6    replace('?',' ').replace('-',' ').replace('\'',' ').\
7    replace('\"',' ').replace('(',' ').replace(')',' ').\
8    replace('',' ').replace(';',' ').split()                         #用空格作为分隔符对将字符串转换为列表 

(3).命令行输入并执行命令 

       作业要求在控制台输入命令并执行,而Python脚本文件无法直接在命令行执行,这里我的做法是将Python脚本(.py)转换为可执行文件(.exe),这样就可以实现命令行输入并执行相应操作,由于实现过程较为繁琐,所以具体的实现过程请参见本人另一篇博客:http://blog.ijunyu.top/2018/09/20/py2exe/#more
(4).命令行参数
      命令行输入功能完成后就要通过命令行参数对程序进行相关的调用,这就类似于函数中的传入参数,所以为Python主函数设置形参,然后将命令行参数传给主函数,主函数根据命令执行相应的操作。Python中主函数的参数假设为argv,是一个列表的形式,列表的第一项为脚本文件的名称,往后是输入的各个参数,正好和命令行参数的输入格式相对应,在具体的操作中,只需要把除了第一个参数之外的其他函数传给主函数就可以,代码如下:
 1 try:
 2     opts, args = getopt.getopt(argv,"sh",["ifile","ofile"])              #设置命令行参数
 3 except getopt.GetoptError:
 4     print("test.py -i <inputfile> -o <outputfile>")
 5     sys.exit(2)
 6 for opt,arg in opts:
 7     if opt == "-s":                                                      #命令行参数为-s时执行的操作
 8         num = len(list)
 9         print('total',num)
10         print('\n')
11         for word in list:
12             print('{:20s}{:>5d}{}'.format(word[0],word[1],'\n'))
13     elif opt == "-h":
14         print("please input the parameter")      
1 if __name__ == "__main__":              #将参数传给主函数main(argv)
2     main(sys.argv[1:])

(5).重复单词的计数

      作业要求重复单词只记一次,并把重复次数记录下来,我采取的办法是使用字典这一数据结构完成这一功能,实现过程为,字典的key为单词,value为出现的次数,依次遍历字符串列表,如果列表元素不在字典中,将字符串加入字典并将该字典元素的value值置1,列表元素在字典中则value值加1,最后将字典的key值根据value值进行排序,就可以得到满足需求的字典,字典元素个数即为total值,字典键值对为单词及其个数,这一功能是整个项目中极为重要的一环,也是个人觉得处理地非常好的地方,是个得意之处,实现代码如下:

1 count_dict = {}                                                             #创建空字典
2   for str in text:                                                         #遍历列表元素
3     if str in count_dict.keys():                         #根据上述逻辑对字典进行键值对的赋值
4       count_dict[str] = count_dict[str] + 1
5     else:
6       count_dict[str] = 1
7 count_list=sorted(count_dict.items(),key=lambda x:x[1],reverse=True)

2.功能一的执行效果截图

3.功能二中的重点和难点

(1).数据量

       根据题目描述,我们就可以看到数据量对于本功能是非常重要的,需要承受40MB的文件大小而不会导致程序崩溃,这对于Python来说不是很大的数据量,所以Python自身就帮助我解决了这一难点。

(2).命令行参数

       本功能相较于功能一,其主要区别就在于命令行参数的变化,命令行只有一个参数,所以,程序必然需要根据参数多少进行相应的功能处理,所以,根据参数个数进行判断也是本功能的重点内容,只需要在原来的基础上加上判断条件就可以了。

4.功能二的执行效果截图

 

       数据量稍大,所以截图主要截了执行的前半部分。

5.功能三中的重点和难点

(1).处理和功能二命令行参数之间的区别

       因为功能三从命令行参数来看和功能二是相似的,但是二者的功能差别由很大,所以区分二者的命令行参数就成为了本功能第一个重点也是难点。这里我采取的方法是使用正则表达式匹配输入的命令行参数,也就是匹配字符串,因为功能二中是txt文件,参数以.txt结尾,功能三是文件夹,名称只是单独的字符串,虽然是比较简单的正则,但是能想到使用正则也是个人的一个得意之处,根据正则表达式所写的代码如下:

1 pattern = re.compile('.+\.txt')           #匹配.txt>结尾的正则表达式
2 folder_name = argv[-1]                    #通过argv传入的参数名称   
3 m = re.findall(pattern,folder_name)       #寻找匹配项
4 if len(m) != 0:                           #如果匹配则列表存在元素,为文件名,执行功能二
5     ...
6 else                                      #如果不匹配则列表不存在元素,为文件夹名,执行功能三
7     ...    

(2).打开文件夹并获取文件名称

       本功能最后要做的还是词频统计,与之前的功能一、二不同的是,本功能需要根据文件夹的名字找出其中包含的文件并且进行词频统计,也就是多了一个进入指定文件夹并执行获取文件名的过程,进入文件夹并获取文件名的具体过程为:一.5.(1)一节中已经完成了对文件夹名称的匹配识别,我们已经得到了文件夹的名称,这时候可以通过os模块中的chdir(path)命令进入文件夹,path即为文件夹的名称,然后还是使用os模块的listdir()命令获取文件名列表,代码如下:

1 os.chdir(folder_name)                #进入folder_name文件夹
2 filename_list = os.listdir()         #获取文件夹中的文件名并生成一个列表

(3).得到文件名后分别计算词频

       进行完之前的步骤后我们得到了文件名,又回到了功能二的范畴,和功能二产生了交集,所以想到可以把整个项目分为几个函数方便重用,所以在原来代码的基础上,我写了2个函数,一个叫做file_read(str),负责读取文件并返回一个包含文档中所有单词的列表,另一个叫做word_count(argv),负责对单词列表进行计数等处理,因为这一重点内容和下一小节联系十分紧密,所以代码和下一小节一起贴出来。

(4).取前十和递归调用

       功能一和二要求列出所有单词,本功能只需要前十,所以本来的word_count(argv)函数无法达到目的,所以我在原有的基础多加了一个标志位,在功能三调用这个函数时单独把标志位置1(初始设为0),当标志位为1时执行取前十操作,标志位为0时取所有元素列表。还有就是文件夹操作和文件读取为了方便我放在了同一个函数中,所以,在得到文件名之后很容易的就可以进行递归操作,完成词频统计及输出的过程,接下来把功能三的完整代码贴出来,如下:

 1 def file_read(str):                                                          #用于读取文件并返回分词之后的单词列表
 2     f = open(str,'r',-1,'utf-8','ignore',None,True,None)
 3     tet = f.read().lower()
 4     text = tet.replace('\n',' ').replace('.',' ').replace(',',' ').\
 5                replace('!',' ').replace('\\',' ').replace('#',' ').\
 6                replace('[',' ').replace(']',' ').replace(':',' ').\
 7                replace('?',' ').replace('-',' ').replace('\'',' ').\
 8                replace('\"',' ').replace('(',' ').replace(')',' ').\
 9                replace('',' ').replace(';',' ').split()
10     count_dict = {}
11     for str in text:
12         if str in count_dict.keys():
13            count_dict[str] = count_dict[str] + 1
14         else:
15            count_dict[str] = 1
16     count_list=sorted(count_dict.items(),key=lambda x:x[1],reverse=True)
17     f.close()
18     return count_list                                                          #返回的分词列表
19 
20 def get_words(argv,flag):                                 #对分完词之后的列表进行计算total、词频、输出等操作                               
21  
22     if len(argv) == 2:                                                         #如果有两个命令行参数
23         try:
24             list = file_read(argv[-1])
25             opts, args = getopt.getopt(argv,"sh",["ifile","ofile"])
26         except getopt.GetoptError:
27             print("test.py -i <inputfile> -o <outputfile>")
28             sys.exit(2)
29         for opt,arg in opts:
30             if opt == "-s":                                                    #如果第一个参数是-s
31                 num = len(list)
32                 print('total',num)
33                 print('\n')
34                 for word in list:
35                     print('{:20s}{:>5d}{}'.format(word[0],word[1],'\n'))
36             elif opt == "-h":
37                 print("please input the parameter")
38     elif len(argv) == 1:                                                       #如果有一个命令行参数
39         pattern = re.compile('.+\.txt')
40         folder_name = argv[-1]
41         m = re.findall(pattern,folder_name)
42         if len(m) != 0:                                                          #参数以.txt结尾,为文件名,直接执行词频操作
43             list = fileRead(argv[-1])
44             if flag == 0:                                                        #标志位为0,把所有单词都列出来
45                 print('total',len(list))
46                 print('\n')
47                 for item in list:
48                     print('{:20s}{:>5d}{}'.format(item[0],item[1],'\n'))
49             else:                                                                #标志位不为0,只列出前十
50                 print('total',len(list), 'words')
51                 print('\n')
52                 if len(list) > 10:
53                     for i in range(10):
54                         print('{:20s}{:>5d}'.format(list[i][0],list[i][1]))
55                 else:                                                            #如果本身不超过10个单词量,则列出所有单词即可
56                     for item in list:
57                         print('{:20s}{:>5d}'.format(item[0],item[1]))
58         else:
59             os.chdir(folder_name)                                                #文件夹操作
60             filename_list = os.listdir()
61             for file_name in filename_list:
62                 print(file_name[:-4] + '\n')
63                 file_list = [file_name]
64                 get_words(file_list,1)                                           #得到文件名,进行递归操作,标志位置1,说明要取前10
65                 print('----\n')
66 
67 def main(argv):
68     get_words(argv,0)
69 
70 if __name__ == "__main__":
71     main(sys.argv[1:])

6.功能三的执行效果截图(文件夹名字为'a')

 7.功能四中的重点和难点

(1).重定向

之前没了解过什么是linux中的重定向,而重定向又是本功能中必不可少的功能,自然而然重定向就成为了本节的重点和难点,那么linux重定向是什么呢?

猜你喜欢

转载自www.cnblogs.com/z1174299705/p/9694560.html