软件工程作业——Word Counter
github地址
https://github.com/Pryriat/Word_Counter
项目说明
wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。
实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:wc.exe [parameter][file_name]基本功能列表:
wc.exe -c file.c//返回文件 file.c 的字符数wc.exe -w file.c//返回文件 file.c 的词的数目wc.exe -l file.c//返回文件 file.c 的行数扩展功能:
-s递归处理目录下符合条件的文件。
-a返回更复杂的数据(代码行 / 空行 / 注释行)。
空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
代码行:本行包括多于一个字符的代码。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
} //注释
在这种情况下,这一行属于注释行。
[filename]:文件或目录名,可以处理一般通配符。
- 高级功能:
-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
- 需求举例:
wc.exe -s -a *.c
返回当前目录及子目录中所有*.c文件的代码行数、空行数、注释行数。
PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 10 | 20 |
| Estimate | 估计这个任务需要多少时间 | 10 | 20 |
| Development | 开发 | 300 | 340 |
| Analysis | 需求分析 (包括学习新技术) | 30 | 60 |
| Design Spec | 生成设计文档 | 10 | 10 |
| Design Review | 设计复审 (和同事审核设计文档) | 0 | 0 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 0 | 0 |
| Design | 具体设计 | 20 | 20 |
| Coding | 具体编码 | 100 | 110 |
| Code Review | 代码复审 | 40 | 40 |
| Test | 测试(自我测试,修改代码,提交修改) | 100 | 100 |
| Reporting | 报告 | 50 | 80 |
| Test Report | 测试报告 | 10 | 10 |
| Size Measurement | 计算工作量 | 10 | 10 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 60 |
| 合计 | 360 | 440 |
解题思路描述

设计实现过程

代码说明
控制台输入输出
#coding = UTF-8
from wc_class import word_counter
from ui_class import wc_ui
import argparse
import sys
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
opt = {}
if len(sys.argv) == 1:
sys.argv.append('-h')# 如果未输入参数,则自动添加执行-h
parser = argparse.ArgumentParser(description='Word_Counter by Chenobyl',add_help=True)
parser.add_argument('-c',help='character counts',action="store_true")
parser.add_argument('-w',help='word counts',action="store_true")
parser.add_argument('-l',help='line counts',action="store_true")
parser.add_argument('-a',help='extra informations',action="store_true")
parser.add_argument('-s',help='match files',action="store_true")
parser.add_argument('-x',help='',action="store_true")
parser.add_argument('-f',default=None,help='input file')
args = parser.parse_args()#参数提取
for x,y in args._get_kwargs():
opt[x]=y
a = word_counter(opt)
if opt['x']:
app = QApplication(sys.argv)
u = wc_ui()
u.show()
sys.exit(app.exec())
elif opt['s']:
a.file_select()
else:
a.file_process(opt['f'])
文件统计类
#coding = UTF-8
import re
import codecs
import getopt
import sys
import glob
class word_counter:
def __init__(self,opt):#用于存储文件统计结果的属性
self.char_num = 0
self.word_num = 0
self.lines = 0
self.nullline = 0
self.single_comment = 0
self.multi_comment = 0
self.code_line = 0
self.is_null = False
self.file = ''
self.opt=opt
def isnull(self,string):
'''
判断文件是否为空
'''
null_pattern = re.compile('.|\s')#判断文件是否有字符
tmp_result = null_pattern.findall(string)
if len(tmp_result) == 0:
return True
return False
def char_count(self,string):
'''
文件字符数统计
'''
return len(string)
def word_count(self,string):
'''
文件单词数统计
'''
word_pattern = re.compile('\S+\s?')#匹配模式:非空白+空白=单词
tmp_result = word_pattern.findall(string)
return len(tmp_result)
def line_count(self,string):
'''
文件行数统计、空行统计与代码行统计
'''
null_line = 0
code_line = 0
sepcial_pattern = re.compile('.*\n?')
tmp_result = sepcial_pattern.findall(string)
for lines in tmp_result:
if len(lines.strip()) == 0 or (len(lines.strip()) == 1 and lines.strip() in ['{','}','#','/','\\','(',')']):#规定中的空白行规则
null_line += 1
elif len(lines.strip())>=1 and lines[0]!= '/':
code_line += 1
return (len(tmp_result)-1,null_line-1,code_line)
def single_comment_count(self,string):
'''
单行注释统计
'''
re_pattern = re.compile('//')
del_pattern = re.compile('"[^"]*//[^"]*"')#排除双引号内情况
multi_in_single_pattern = re.compile('/\*.*')#排除多行注释内情况
tmp_result1 = re_pattern.findall(string)
tmp_result2 = del_pattern.findall(string)
for lines in tmp_result1:
if len(multi_in_single_pattern.findall(lines)) == 1:
self.multi_comment -= 1
print('sig',len(tmp_result1) - len(tmp_result2))
return len(tmp_result1) - len(tmp_result2)
def multi_comment_count(self,string):
'''
多行注释统计
'''
multi_lines = 0
del_lines = 0
multi_pattern = re.compile('/\*+[^\*]+\*/')
single_in_multi_pattern = re.compile('//.*')#排除单行注释内情况
del_pattern = re.compile('"[^"]*/\*[^"]*\*/')#排除双引号内情况
tmp_result = multi_pattern.findall(string)
for result1 in tmp_result:
self.single_comment -= len(single_in_multi_pattern.findall(result1))
for x in result1:
if x == '\n':
multi_lines+=1
del_result = del_pattern.findall(string)
for x in del_result:
if x == '\n':
del_lines += 1
return multi_lines - del_lines
def file_process(self,file):
'''
文件处理主函数
'''
with codecs.open(file, 'r', 'utf-8') as f:
self.file_string = f.read()
print('file:'+file,end=' ')
if self.isnull(self.file_string):
print('null file!')
return
else:
self.multi_comment += self.multi_comment_count(self.file_string)
self.single_comment += self.single_comment_count(self.file_string)
self.char_num += self.char_count(self.file_string)
self.word_num += self.word_count(self.file_string)
(self.lines,self.nullline) = self.line_count(self.file_string)
(self.lines,self.nullline,self.code_line) = self.line_count(self.file_string)
if self.opt['a'] :
print('character:'+str(self.char_num),end = ' ')
print('words:'+str(self.word_num),end=' ')
print('lines:'+str(self.lines),end=' ')
print('code_line:'+str(self.code_line),end=' ')
print('null_line:'+str(self.nullline),end=' ')
print('comment_line:'+str(self.single_comment+self.multi_comment))
else:
if not (self.opt['c'] or self.opt['w'] or self.opt['l']):
print('Please input command\n')
return
if self.opt['c']:
print('character:'+str(self.char_num),end = ' ')
if self.opt['w']:
print('words:'+str(self.word_num),end=' ')
if self.opt['l']:
print('lines:'+str(self.lines),end=' ')
def file_select(self):#文件匹配
print(self.opt['f'])
file_list = glob.glob(self.opt['f'])
for x in file_list:
self.file_process(x)
图形界面类
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from wc_class import word_counter
class wc_ui(QDialog):
def __init__(self, parent=None):#控件初始化
super().__init__()
self.opt = opt = {'a':True}
self.wc = word_counter(self.opt)
self.setWindowTitle('Word Counter by Chernobyl')
self.file_label = QLabel()
self.is_null_label = QLabel('isnull:')
self.character_label = QLabel('character:')
self.word_label = QLabel('word:')
self.line_label = QLabel('line:')
self.null_line_label = QLabel('null_line:')
self.code_line_label = QLabel('code_line:')
self.comment_line_label = QLabel('comment_line:')
self.mainlayout = QVBoxLayout()
self.file_button = QPushButton('select file')
self.file_button.clicked.connect(self.selectfile)
self.mainlayout.addWidget(self.file_label)
self.mainlayout.addWidget(self.is_null_label)
self.mainlayout.addWidget(self.character_label)
self.mainlayout.addWidget(self.word_label)
self.mainlayout.addWidget(self.line_label)
self.mainlayout.addWidget(self.null_line_label)
self.mainlayout.addWidget(self.code_line_label)
self.mainlayout.addWidget(self.comment_line_label)
self.mainlayout.addWidget(self.file_button)
self.setLayout(self.mainlayout)
def selectfile(self):#选择文件,并获取所有信息,更新控件的显示值
file_name = QFileDialog.getOpenFileName(self,"select file ","C:\\","c source files(*.c);;cpp source files(*.cpp);;header files(*.h)")
self.wc.file_process(file_name[0])
self.file_label.setText('file: %s'%(file_name[0]))
self.is_null_label.setText('isnull: %s'%(str(self.wc.is_null)))
self.character_label.setText('character: %d'%(self.wc.char_num))
self.word_label.setText('word: %d'%(self.wc.word_num))
self.line_label.setText('line: %d'%(self.wc.lines))
self.code_line_label.setText('code_line: %d'%(self.wc.code_line))
self.comment_line_label.setText('comment_line: %d'%(self.wc.single_comment+self.wc.multi_comment))
self.null_line_label.setText('null_line: %d'%(self.wc.nullline))
运行截图
按照题目要求所创建的5个文件——空白、一个字母、一个单词、一整行、普通文件。截图如下

软件帮助界面如下

使用ubuntu内置的wc工具结果如下。注意,猜测wc工具的匹配规则为结尾有换行符算作一行——这是个bug,因为示例一行文件中虽然结尾无换行符,但应算作一行

使用自己实现的wc工具结果如图

图形界面截图如下


项目小结
- 发现了在进行软件项目时的诸多问题,如进度管控、功能实现、debug等
- 发现了wc工具的"bug"
- 熟悉了python的图形界面编写和程序打包
软件工程作业——Word Counter的更多相关文章
- 软件工程作业 - word count
(编程和软件工程作业系列) 实践最简单的项目:WC 实践是理论的基础和验证标准,希望读者贯彻“做中学”的思想,动手实现下面的项目,并和别人的成绩相比较,分析产生差距的原因. 1. 实现一个简单而完整的 ...
- 在大型软件中用Word做报表: 书签的应用
本文转载:http://www.cnblogs.com/huyong/archive/2011/08/24/2151599.html 报表基本上在每一个项目中占有很大的比例,做报表也是我们开发人员必须 ...
- OFFICE2007软件打开word时出现SETUP ERROR的解决方法
今天打开word时出现以下错误窗口: 在度娘上找了一下解决方案,原来每次打开word时都会启动一些无用的东西,找到这些东西的路径D:\Program Files\Common Files\micros ...
- 第一次软件工程作业——html制作一份简单的个人简历
源码链接(码云):https://gitee.com/yongliuli/codes/eavjr7lxotb85s0icnq1z68 简历效果图展示: 代码展示: 添加背景音乐的方法: 在<he ...
- 第一次软件工程作业(One who wants to wear the crown, Bears the crown.)
回顾你过去将近3年的学习经历 1.当初报考的时候,是真正的喜欢计算机这个专业吗? 报考时对于计算机专业只能说不讨厌,也可以认为对其没有任何的感觉. 有一个比我自己还注意我未来的老妈,我的报考只能通过一 ...
- 软件工程作业 - Week 1
构建之法读后疑问: 初步的完成构建程序设计思路之后实现过程中发现了问题或者可以优化的地方是立马就改进还是完成之后按照步骤统一进行优化. 覆盖性测试,针对一些永远用不到只是用来预防极为极端的情况下,例如 ...
- 关于Office软件中Word输入时卡顿无反应的解决办法!
最近在安装office2013时遇到了这样一个问题,就是在激活office之后,打开Word输入内容时十分卡顿.也是狂搜网上各种办法,有说改注册表的,也有说在office选项里设置什么输入法的,全试了 ...
- 第一次软件工程作业补充plus
一.代码的coding地址:coding地址. 二.<构建之法>读后问题以及感言(补充): 1.对于7.3MSF团队模型,7.2.6保持敏捷,预期和适应变化,中的"我们是预期变化 ...
- 软件工程作业0——The Road Not Taken
目录 第一部分:结缘计算机 缘起 四顾 思考 第二部分:在计算机系里学习 挑战 落差 第三部分:未来规划 向前 未来四个月的软工课 项目 内容 这个作业属于 2020春季计算机学院软件工程(罗杰 任健 ...
随机推荐
- kafka source type
https://flume.apache.org/FlumeUserGuide.html # example.conf: A single-node Flume configuration # Nam ...
- The Log-Structured Merge-Tree (LSM-Tree
https://www.cs.umb.edu/~poneil/lsmtree.pdf [Log-Structured Merge-Tree ][结构化日志归并树][要解决的问题]The Log-S ...
- 如何在ubuntun中安装pycharm并将图标显示在桌面上
安装pycharm首先要安装jdk. 可以通过java -V来查看是否安装了jdk.安装jdk的方法如下: 1 首先在oracle网站下载jdk,现在jdk是1.8的. 2 新建一个/usr/lib/ ...
- Android/iOS Remote debugging
简单介绍 使用下面方法可以定位webview中的元素,无法定位view中的元素. 原文地址:http://mp.weixin.qq.com/s/y_UfdgjT_pkKgYivJmqt7Q webvi ...
- 《CSS权威指南(第三版)》---第三章 结构和层叠
这章主要讲的是当某个对象被选择器多次提取使用样式之后的一些冲突性解决方案: 1.特殊性:指的是当多个效果作用的时候的最终选择: 这个规则用0,0,0,0来比较.其中:内联式是1,0,0,0 ID选择 ...
- .gitignore文件配置:keil工程文件类型【转】
本文转载自:https://blog.csdn.net/u010160335/article/details/80043965 .gitignore源文件下载链接:git管理keil工程.gitign ...
- 用ant编译打包时 警告:编码 GBK 的不可映射字符
原因,参考http://zhidao.baidu.com/question/26901568.html 添加如下的红色一行后编译通过<target name="compile" ...
- JS如何定义方法及调用 精选
简单搜索了下,遇到点问题1,经常在JS中看到如var foo = function(){}的形式foo是方法名还是对象名,如果想调用此方法,是用foo(),foo.function(),还是该如何正确 ...
- java异常的原理以及应用
父类Throwable 两个分支: error:合理的应用程序不应该出现的严重问题,可以无需声明便抛出,比如内存溢出. Exception:程序还能够克服和恢复的问题. 其中又分为系统异常和普通异常. ...
- Java集合的有序无序问题和线程安全与否问题
首先,清楚有序和无序是什么意思: 集合的有序.无序是指插入元素时,保持插入的顺序性,也就是先插入的元素优先放入集合的前面部分. 而排序是指插入元素后,集合中的元素是否自动排序.(例如升序排序) 1.有 ...