Python实现字符,单词,行,代码行,空行及可视化

Gitee项目地址:https://gitee.com/biubiubiuLYQ/word_and_character_statistics

一.解题思路

  一开始拿到该题目,心想最近在学Shell编程,好像写个脚本,用wc命令都可以较轻松的把这些功能实现,但是这好像要得是具体去模拟wc命令,让自己更了解是如何实现的,一想,基本功能都挺好实现的,就是从没实现过带命令参数的程序,也不知道py文件打包成exe文件该如何实现,于是百度了一下,发现实现方法还挺多,那还等什么,于是便开干了......

二.程序设计实现过程

  1.基本功能:

    写了三个函数,一个函数only_one()是参数只有文件,我默认将字符数,单词数,行数写进与wc.exe文件下的同目录下的result.txt文件里,第二个函数是include_many_minglin(file_path,out_file)判断带命令(-w,-l,-c,-o)参数的,还未写扩展功能时,我也只给定一个参数,首先验证所带参数是否合法(命令重复或命令参数无法识别),验证成功之后继续验证是否带“-o”参数,因为两种情况不一样,如若不带“-o”参数,则所读取的文件为参数的最后一个,而带“-o”参数,则所读取的文件为倒数第三个,最后一个命令参数为结果写进的文件。第三个函数是out_nominglin(file_path)用来接受输出结果指定文件,默认为wc.exe当前目录下的result.txt文件。

  2.扩展功能:

    扩展功能都是基于基本功能实现的,重写了include_many_minglin(file_path,out_file,stop_txt_file=''),首先添加了判断命令是否带“-a”,若带该参数,则也保存代码行,空行,注释行,然后添加了停止词参数然后判断是否带命令参数“-e”,若有则读取停止词,将所读文件中的单词把停止词排除然后计数,还添加了函数getallfile(path),若命令参数中含“-s”,则遍历当前目录及子目录获取所有文件,另外一个函数是tomgpei(re_file),用于匹配文件名是否满足条件,并提取。

  2.高级功能:

    这是我单独做的模块,用的GUI,添加了一个类App(),该类主要用来显示可视框并实现点击按钮选择文件并显示文件的字符数,单词数,行数等信息,判断命令参数只有一个且为“-x”时,实列化类并执行。

三.代码说明

  1.命令参数只有文件时的函数:

    获取文件名,然后读取文件,获取字符数,单词数(用正则模块以“,”和空格分割),行数(以"\n"分割)并写进文件(file_path我配置为与wc.py同目录下的result.txt)。

  1. def only_one():
  2. '''
  3. 无命令参数时,写入文件单词,字符,行数
  4. :return:
  5. '''
  6. file_path = sys.argv[-1]
  7. try:
  8. with open(file_path, 'r') as fp:
  9. all_text = fp.read()
  10. zifu = len(all_text)
  11. words = len(re.split('[\s,]', all_text))
  12. hangs = len(all_text.split('\n'))
  13. with open(result_path, 'a', encoding='utf-8') as fp2:
  14. fp2.write(sys.argv[-1] + ',' + '字符数:' + str(zifu) + '\n')
  15. fp2.write(sys.argv[-1] + ',' + '单词数:' + str(words) + '\n')
  16. fp2.write(sys.argv[-1] + ',' + '行数:' + str(hangs) + '\n')
  17.  
  18. fp.close()
  19. except:
  20. print('参数为一个时只能是文件或文件路径!' + '请检查参数是否正确或文件是否正确!')

  2.含命令参数('-c','-l','-w','-a'):

    首先在主函数验证过后,命令参数合法才调用该函数,out_file为输出结果的文件(默认为result.txt),stop_txt_path代表停止词文件路径,如果命令参数带"-o"且命令格式正确,,若stop_txt_path不为空则读取该停止词文件,以逗号分割成若干个字符串,然后读取要读取的文件,验证是否有单词与停止词文件中字符串相同,若有则全部移除,最后将移除停止词后的文件单词计数。其他"-l",'"-w","-c"判断也是命令合法后然后若命令包含它,则在文件中保存相关信息。

  1. def include_many_minglin(file_path, out_file=result_path, stop_txt_path=''):
  2. '''
  3. 包含多个参数时:
  4. file_path:被读取文件的路径
  5. out_file:输出结果输入的文件路径
  6. :param file_path:
  7. :param out_file:
  8. :return:
  9. '''
  10. try:
  11. with open(file_path, 'r') as fp:
  12. all_text = fp.read()
  13. all_minglin = sys.argv[1:-1]
  14. if '-c' in all_minglin:
  15. zifu = len(all_text.strip())
  16. try:
  17. with open(out_file, 'a', encoding='utf-8') as fp2:
  18. fp2.write(file_path + ',字符数:' + str(zifu) + '\n')
  19. fp2.close()
  20. except:
  21. print('输出文件打开或创建失败!')
  22. exit()
  23. # print('字符数:' + str(zifu))
  24. if '-w' in all_minglin:
  25. words = re.split('[\s,,]', all_text)
  26. try:
  27. if stop_txt_path:
  28. try:
  29. with open(stop_txt_path, 'r') as stops:
  30. stop_words = stops.read().split()
  31. with open(out_file, 'a', encoding='utf-8') as fp2:
  32. for word in words:
  33. if word in stop_words:
  34. words.remove(word)
  35. else:
  36. pass
  37. fp2.write(file_path + ',单词数:' + str(len(words)) + '\n')
  38. fp2.close()
  39. stops.close()
  40. except:
  41. print('停止词文件打开失败!!')
  42. else:
  43. with open(out_file, 'a', encoding='utf-8') as fp2:
  44. fp2.write(file_path + ',单词数:' + str(len(words)) + '\n')
  45. fp2.close()
  46. except:
  47. print('输出文件打开或创建失败!')
  48. exit()
  49. if '-l' in all_minglin:
  50. hangs = len(all_text.split('\n'))
  51. try:
  52. with open(out_file, 'a', encoding='utf-8') as fp2:
  53. fp2.write(file_path + ',行数:' + str(hangs) + '\n')
  54. fp2.close()
  55. except:
  56. print('输出文件打开或创建失败!')
  57. exit()
  58. # print('行数:' + str(hangs))
  59. if '-a' in all_minglin:
  60. control_data = ['%', '-', 'm.n', 'l', 'h']
  61. hangss = all_text.split('\n')
  62. null_ = True
  63. code = 0
  64. nulls = 0
  65. zhushi = 0
  66. for hang in hangss:
  67. if len(hang) > 1:
  68. for every_data in hang:
  69. if every_data in control_data:
  70. pass
  71. else:
  72. null_ = False
  73. break
  74. if null_ == True or hang == '{' or hang == '}' or len(hang) == 0:
  75. nulls += 1
  76. else:
  77. if '//' in hang or '/*' in hang:
  78. zhushi += 1
  79. else:
  80. code += 1
  81. with open(out_file, 'a', encoding='utf-8') as fp2:
  82. fp2.write(file_path + ',' + '代码行/空行/注释行:' + str(code) + '/' + str(nulls) + '/' + str(zhushi) + '\n')
  83. fp2.close()
  84. fp.close()
  85. except:
  86. print('你的文件路径或文件格式错误,无法打开该文件,请检查后再次输入!!!')

  3.遍历所在目录及子目录获取所有文件并筛选符合条件的: 

    若命令参数带"-s",首先通过getallfile获取当前目录及子目录所有文件,然后通过tomgpei验证符合条件的文件,若参数本身是一个目录,则默认获取该目录及子目录下的所有文件并返回,否则(我这里写的通配符只写了*),及以*分割参数,然后判断文件名是否符合条件(包含以*分割的所有字符串)。

  1. def getallfile(path):
  2. '''
  3. 递归获取目录下所有文件
  4. :param path:
  5. :return:
  6. '''
  7. allfilelist = os.listdir(path)
  8. for file in allfilelist:
  9. filepath = os.path.join(path, file)
  10. # 判断是不是文件夹
  11. if os.path.isdir(filepath):
  12. getallfile(filepath)
  13. else:
  14. allfile.append(filepath)
  15. return allfile
  16.  
  17. def tomgpei(re_file):
  18. '''
  19. 通配符匹配
  20. :param re_file:
  21. :return:
  22. '''
  23. if os.path.exists(re_file):
  24. if os.path.isdir(re_file):
  25. allfiles = getallfile(re_file)
  26. return allfiles
  27. elif os.path.isfile(re_file):
  28. all = []
  29. all.append(re_file)
  30. return all
  31. else:
  32. print('不是文件名或目录!')
  33. return None
  34. elif '*' in re_file:
  35. all_txts = []
  36. allfiles = getallfile(Now_Dir)
  37. split_datas = re_file.split('*')
  38. for file in allfiles:
  39. y_n = True
  40. for split_data in split_datas:
  41. if split_data in file:
  42. pass
  43. else:
  44. y_n = False
  45. if y_n == True:
  46. all_txts.append(file)
  47. else:
  48. pass
  49. return all_txts
  50. else:
  51. print('目录或文件不存在!')
  52. return None

  4.可视化实现:

    这里是GUI的一些简单用法,具体就是添加了两个按钮(一个退出,一个选择文件),并绑定了相应的函数,一个是退出按钮自带的关闭弹出框的函数frame.quit,选择文件按钮绑定的是chose_wenjian函数,用于选择文件并对文件相关信息统计然后动态加入txt文本框中。

  1. class App:
  2. '''
  3. gui实现可视化
  4. '''
  5.  
  6. def __init__(self, master):
  7. # 构造函数里传入一个父组件(master),创建一个Frame组件并显示
  8. frame = Frame(master)
  9. frame.pack()
  10. # 创建两个button,并作为frame的一部分
  11. self.wenjian_path = StringVar()
  12. self.label = Label(text="文件路径: ")
  13. self.label.pack(side=TOP)
  14. self.entry = Entry(textvariable=self.wenjian_path)
  15. self.entry.pack(side=TOP)
  16. self.button = Button(frame, text="退出", fg="red", command=frame.quit, anchor='sw')
  17. self.button.pack(side=RIGHT) # 此处side为LEFT表示将其放置 到frame剩余空间的最左方
  18. self.hi_there = Button(frame, text="选择文件", fg='red', command=self.chose_wenjian, anchor='se')
  19. self.hi_there.pack(side=LEFT)
  20. self.label = Label(text="文件信息显示: ")
  21. self.label.pack(side=TOP)
  22. self.txt = Text(width=55, height=15)
  23. self.txt.pack()
  24.  
  25. def chose_wenjian(self):
  26. paths = askopenfile()
  27. self.wenjian_path.set(paths.name)
  28. if paths:
  29. self.txt.delete(0.0, tkinter.END)
  30. try:
  31. with open(paths.name, 'r') as f:
  32. all_contents = f.read()
  33. zifu = len(all_contents)
  34. words = len(re.split('[\s,]', all_contents))
  35. hangs = len(all_contents.split('\n'))
  36. control_data = ['%', '-', 'm.n', 'l', 'h']
  37. null_ = True
  38. code = 0
  39. nulls = 0
  40. zhushi = 0
  41. hangss = all_contents.split('\n')
  42. for hang in hangss:
  43. if len(hang) > 1:
  44. for every_data in hang:
  45. if every_data in control_data:
  46. pass
  47. else:
  48. null_ = False
  49. break
  50. if null_ == True or hang == '{' or hang == '}' or len(hang) == 0:
  51. nulls += 1
  52. else:
  53. if '//' in hang or '/*' in hang:
  54. zhushi += 1
  55. else:
  56. code += 1
  57. self.txt.insert(END, "字符数:" + str(zifu) + "\n")
  58. self.txt.insert(END, "单词数:" + str(words) + "\n")
  59. self.txt.insert(END, "行数:" + str(hangs) + "\n")
  60. self.txt.insert(END, "代码行数:" + str(code) + "\n")
  61. self.txt.insert(END, "空行数:" + str(nulls) + "\n")
  62. self.txt.insert(END, "注释行数:" + str(zhushi) + "\n")
  63.  
  64. except:
  65. self.txt.insert(END, "文件打开失败,请检查文件格式是否正确!!!")
  66. else:
  67. pass

  5.判断命令参数是否合法,并获取相关信息:

    判断参数是否存在,是否重复,是否含“-s”,“-o”,"-e",若含有则修改相应状态(False/True),并在后续调用不同的函数。

  1. # 默认无结果输出文件
  2. data_out_txt = False
  3. # 默认为停止词文件
  4. data_stop_txt = False
  5. #是否含需要遍历目录
  6. DIGUI = False
  7. if len(sys.argv) <= 1:
  8. print('命令格式不正确!!!')
  9. elif len(sys.argv) == 2:
  10. if sys.argv[-1] == '-x':
  11. win = Tk()
  12. win.geometry('500x310+500+200')
  13. # 设置窗口标题
  14. win.title('文件检索')
  15. app = App(win)
  16. win.mainloop()
  17. else:
  18. only_one()
  19. else:
  20. minglin = ['-c', '-w', '-l', '-o', '-s', '-a', '-e']
  21. for i in sys.argv[1:-1]:
  22. if i not in minglin and sys.argv[sys.argv.index(i) - 1] == '-o':
  23. pass
  24. elif i not in minglin and sys.argv[sys.argv.index(i) - 1] == '-e':
  25. pass
  26. elif i not in minglin and "-s" in sys.argv[1:sys.argv.index(i)]:
  27. pass
  28. else:
  29. if i in minglin and sys.argv.count(i) == 1 and i != '-o' and i != '-e' and i!='-s':
  30. pass
  31. elif i in minglin and sys.argv.count(i) > 1:
  32. print('命令重复!!请修改!')
  33. # break
  34. exit()
  35. elif sys.argv.count(i) == 1 and i == '-o':
  36. data_out_txt = True
  37. elif sys.argv.count(i) == 1 and i == '-e':
  38. data_stop_txt = True
  39. stop_txt_path = sys.argv[sys.argv.index(i) + 1]
  40. elif sys.argv.count(i) == 1 and i == '-s':
  41. DIGUI = True
  42. else:
  43. print('命令格式错误!!!')
  44. # break
  45. exit()

四.测试设计过程(路径覆盖)

  1.基本功能测试: 

    1.1返回字符数:wc.exe -c G:\main.c

    1.2返回单词数:wc.exe -w G:\main.c

    1.3返回行数:wc.exe -l G:\main.c

    1.4返回字符数和单词数:wc.exe -c -w G:\main.c

    1.5返回字符数和行数:wc.exe -c -l G:\main.c

    1.6返回单词数和行数:wc.exe  -w -l G:\main.c

    1.7返回字符数,单词数,行数:wc.exe -c -w  -l G:\main.c

所有测试命令

结果

    1.8测试输出结果到指定文件(字符数):wc.exe -c G:\main.c -o outfile.txt    

    1.9测试输出结果到指定文件(单词数):wc.exe -w G:\main.c -o outfile.txt

    1.10测试输出结果到指定文件(行数):wc.exe -l G:\main.c -o outfile.txt

    1.11测试输出结果到指定文件(字符数和单词数):wc.exe -c -w G:\main.c -o outfile.txt    

    1.12测试输出结果到指定文件(字符数和行数):wc.exe -c -l G:\main.c -o outfile.txt

    1.13测试输出结果到指定文件(单词数和行数):wc.exe -w -l G:\main.c -o outfile.txt

    1.14测试输出结果到指定文件(单词数,字符数,行数):wc.exe -c -w -l G:\main.c -o outfile.txt

测试命令

结果

  2.扩展功能测试:

    2.1遍历目录及子目录符合条件的文件(输出字符数):wc.exe -s -c   *.txt

测试命令

结果

    2.2遍历目录及子目录符合条件的文件(输出字符数及单词数):wc.exe -s -c -w   *.txt

测试命令

结果

    2.3遍历目录及子目录符合条件的文件(输出字符数,单词数,行数):wc.exe -s -c -w -l  *.txt

测试命令

结果

    2.4遍历目录及子目录符合条件的文件(输出字符数,单词数,行数并到指定文件):wc.exe -s -c -w -l  *.txt -o G:/all_results.txt

测试用例

结果

    2.4处理复杂的代码行(只返回代码行,空行,注释行):

测试用例

结果

    2.5返回字符数,单词数,行数,复杂数据:

测试用例

结果

    2.6 返回字符数,单词数,行数,复杂数据到指定文件:

 

测试用例

输出结果

    2.7遍历目录及子目录下的满足条件的文件,并输出复杂数据:

测试用例

结果

    2.8遍历目录及子目录下的满足条件的文件,并输出复杂数据到指定文件:

测试用例

结果

    2.9遍历目录及子目录下的满足条件的文件,并输出复杂数据,字符数,单词数,行数:

测试用例

结果

    2.10遍历目录及子目录下的满足条件的文件,并输出复杂数据,字符数,单词数,行数到指定文件:

测试用例

结果

    2.11排除停止词输出单词数:

测试命令

结果验证正确

    2.12返回当前目录及子目录中所有.txt文件的字符数、单词总数、代码行数、空行数、注释行数,并将结果保存在output.txt中,且统计单词时忽略stop.txt中的单词:

测试命令

结果

  3.高级功能测试:

测试命令

弹出框

选择文件后显示信息

选择其他文件会覆盖上一文件信息

五.目前的问题:

    1.打包成exe文件后程序运行比Python环境下运行py文件慢很多;

    2.打包成exe文件后默认的result.txt文件不会创建在于wc.exe文件下的同目录中,而是创建在当前所在文件夹下,而运行原py文件会创建在于wc.py文件下的同目录中;

    3.若在遍历目录下文件时,把输出结果文件创建在当前目录下会阻塞。

六.参考文献

    Tkiner的简单使用:http://www.runoob.com/python/python-gui-tkinter.html

    Python打包成exe文件:https://blog.csdn.net/u010812071/article/details/78507946

     

    

Python模拟wc命令(软件测试第二次作业)的更多相关文章

  1. 逐步实现python版wc命令

    Python 如何处理管道输入输出 sys.stdin 等于打开了一个文件对象,所有输入的文件都会写入到标准输入文件中(键盘) sys.stdout 等于打来了一个文件对象,使用.write()把信息 ...

  2. 使用 python 实现 wc 命令程序的基本功能

    这里使用了 python 的基本代码实现了 Linux 系统下 wc 命令程序的基本功能. #!/usr/bin/env python #encoding: utf-8 # Author: liwei ...

  3. 作业(二)—python实现wc命令

    Gitee地址:https://gitee.com/c1e4r/word-count(为什么老师不让我们用github) 0x00 前言 好久没发博客了,感觉自己的学习是有点偷懒了.这篇博客也是应专业 ...

  4. 软件测试第二周作业 WordCount

    本人github地址:  https://github.com/wenthehandsome23 psp阶段 预估耗时 (分钟) 实际耗时 (分钟) 计划 30 10 估计这个任务需要多少时间 20 ...

  5. 软件测试第二次作业——Fault,Failure,Error辨析与设计测试用例

    Fault 静态错误 ,Failure 外部错误 ,Error 内部错误 问题答案 第一题 1.1 当数组x内的元素≥2时,该循环不会检测到x[0]这个元素. 1.2 test: x=[2, 3, 2 ...

  6. 软件测试第二次作业:初识JUNIT单元测试方法

    软件测试有很多分类,从测试的方法上可分为:黑盒测试.白盒测试.静态测试.动态测试   从软件开发的过程分为:单元测试.集成测试.确认测试.验收.回归等. 在众多的分类中,与开发人员关系最紧密的莫过于单 ...

  7. 2003031121-浦娟-python数据分析第四周作业-第二次作业

    项目 内容 课程班级博客链接 20级数据班(本) 作业链接 Python第四周作业第二次作业 博客名称 2003031121-浦娟-python数据分析第四周作业-matolotlib的应用 要求 每 ...

  8. python学习:简单的wc命令实现

    #!/usr/bin/python   import sys import os   try:     fn = sys.argv[1] except IndexError:     print &q ...

  9. 第二课作业——redis常用命令

    第二课时作业 静哥 by 2016.2.23~2016.2.22   [作业描述] 1.key string list hash结构中,每个至少完成5个命令,包含插入 修改 删除 查询,list 和h ...

随机推荐

  1. python入门学习:3.操作列表

    python入门学习:3.操作列表 关键点:列表 3.1 遍历整个列表3.2 创建数值列表3.3 使用列表3.4 元组 3.1 遍历整个列表   循环这种概念很重要,因为它是计算机自动完成重复工作的常 ...

  2. Leetcode:0027

    Leetcode:0027 题目:给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度.不要使用额外的数组空间,你必须在原地修改输入数组并在使用 ...

  3. SpringBoot注册登录(三):注册--验证账号密码是否符合格式及后台完成注册功能

    SpringBoot注册登录(一):User表的设计点击打开链接SpringBoot注册登录(二):注册---验证码kaptcha的实现点击打开链接      SpringBoot注册登录(三):注册 ...

  4. Oracle补丁术语介绍

    在使用Oracle的技术支持服务的时候,经常会遇到补丁相关的术语.现在对这些术语做些解释说明: Interim patch/One-off patch:是我们常说的小补丁,为了修复某(几)个Bug而发 ...

  5. WiFi-ESP8266入门http(2-1)文件系统-复杂结构的网页

    https://blog.csdn.net/solar_Lan/article/details/74231360 用到的网页文件:链接:https://pan.baidu.com/s/1vk6xmsY ...

  6. ExFilePicker的使用 — 获取本地图片资源并用RecyclerView展示出来

    代码其实很简单,所以就不多进行文字说明,直接上完整的代码: 第一步:在app/build.gradle添加需要使用到的依赖库:(这里对引用的版本冲突问题作了处理,详情请看链接:https://www. ...

  7. object detection[SSD]

    0. 背景 经过了rcnn,spp,fast rcnn, faster rcnn,yolo,这里又到了ssd模型. faster rcnn的贡献是将候选框区域提取的部分也集成到CNN中去,并且与对象的 ...

  8. face detection[Face R-CNN]

    face r-cnn是腾讯ai实验室的作品,而且登录过腾讯ai实验室官网,发现果然硕果累累,不得不佩服. 1 引言 人脸检测虽然相对之前有了不小的进步,可是还是因为真实世界中人脸图像的明显变化导致仍然 ...

  9. Spring-boot 编写hello world

    项目启动时出现如下报错信息: Unrecognized VM option 'TieredStopAtLevel=1' Could not create the Java virtual machin ...

  10. 史上最全面的Neo4j使用指南

    Neo4j图形数据库教程 Neo4j图形数据库教程 第一章:介绍 Neo4j是什么 Neo4j的特点 Neo4j的优点 第二章:安装 1.环境 2.下载 3.开启远程访问 4.测试 第三章:CQL 1 ...