个人项目作业

1. Github项目地址

 https://github.com/DFRUfO/one-onion

2.1 WC 项目要求

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 返回更复杂的数据(代码行 / 空行 / 注释行)。

空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。

代码行:本行包括多于一个字符的代码。

注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:

} //注释

在这种情况下,这一行属于注释行。

[file_name] : 文件或目录名,可以处理一般通配符。

高级功能:

-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

2.2 实现程序前,模块开发预计时间

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30  
Estimate 估计这个任务需要多少时间 30  
Development 开发 800  
Analysis 需求分析(包括学习新技术) 60  
Design Spec 生成设计文档 20  
Design Review 设计复审    
Coding Standard 代码规范 20  
Design 具体设计 30  
Coding 具体编码 300  
Code Review 代码复审 20  
Test 测试(自我测试、修改代码、提交修改) 200  
Reporting 报告 60  
Test Report 测试报告 30  
Size Measurement 计算工作量 10  
Postmortem&Process Improvement Plan 事后总结,并提出过程改进计划 30  
Total 合计 1610   

3. 解题思路

编程语言的选择

最近在学习python,觉得python比较方便好用,内含的库较多,可直接使用,因此选择python进行这次作业的开发。

需要用到的知识

控制命令行传参数、tkinter、字典、I/O流、正则表达式

结构分析

看到有较多的功能,所以不能将所有的程序写在一个py文件,要将必要的功能进行封装,需要时再调用,所以只需要一个主程序,去调用其他字程序就行了。

遇到的困难

有时候总是把程序写死,不够灵活,解决起来费时间,命令行传参不是很懂,开始时出错,python的图形界面也是刚开始学,编码特别慢,现学现做,效果不是很好,还有就是不知道如何打开资源管理器,花了很多时间。

4. 设计实现过程

根据需求,对每个功能进行细分、简化,找出每个功能的详细需求,把每个功能都实现完成,生成函数,然后考虑封装调用,在主函数中实现调用各个功能函数,完成开发。

函数调用

5. 代码说明

1)主程序

import sys
import output as op
from window import Window
def main():
    """主程序"""
    file = sys.argv[2]  #从命令行中获取参数文件名
    command  = sys.argv[1]
    file_name = file
    if command == '-x':
        Window()
    op.Output(command,file_name)
main()

2)Output()函数:根据命令行的参数对应输出或者调用

def Output(command,file_name):
"""选择命令,输出数据"""
datas = count(file_name)
if command == '-c':
export(file_name,"字符数",datas['character'])
elif command == '-w':
export(file_name, "单词数", datas['word'])
elif command == '-l':
export(file_name, "行数", datas['line'])
elif command == '-s': #处理目录下符合条件的文件
print(" C:\Users\荣\PycharmProjects\homework目录下的文件统计: ")
recursion()
elif command == '-a':
print(' 文件%s下的统计:' % file_name)
print(datas)
else:
print("请输入正确指令")

def export(filename,name,data):
print('文件名:%s, %s: %d' % (filename,name,data))

3)count()函数,实现统计的功能,计算行数、字符数、代码数,利用字典存储数据,返回。

     简要说明:首先利用open函数打开文件,然后对文件中每行进行循环,如果去掉每行两端的空白后等于空,则空行数加1;如果这行含有“//”,则注释行加1;计算单词数的时候,先用空格代替其他特殊符号,利用split()函数通过空格使每行分隔开成为一个列表,使用正则判断是否为单词,如果是,则单词数加1。

def count(file_name):
"""统计文件中的数据"""
data = {}
data['line'] = 0
data['word'] = 0
data['character'] = 0
data['empty_line'] = 0 #空行
data['note_line'] = 0 #注释行
data['code_line'] = 0 #代码行
try:
with open(file_name, 'r', encoding='utf-8')as fi:
for lines in fi:
if lines.strip() == '':
data['empty_line'] += 1
continue
if '//' in lines:
data['note_line'] += 1

replace = re.subn(r"[#<>,;()""&{}+]"," ",lines) #用空格代替替他符号
words = replace[0].split()
data['line'] += 1
for word in words:
if re.match(r".*[A-Za-z].*",word):
data['word'] += 1
if data['word'] > 1:
data['code_line'] += 1
data['character'] += len(lines) - 1
except Exception as err:
print(err)
finally:
fi.close()
return data

4)recursion()函数,调用getfile()函数,获得文件名,利用循环处理目录下符合条件的文件,输出数据。

def recursion():
    """处理目录下符合条件的文件"""
    file_list = getfile()
    for filename in file_list:
        datalist = count(filename)
        print("文件名:%s" % filename)
        print(datalist)

5)getfile()函数,利用os的功能walk找到目录下符合条件的所有文件。

def getfile():
    """处理目录下符合条件的文件,返回文件名"""
    g = os.walk(r"C:Users荣PycharmProjectshomework")
    files = []
    for path,d,filelist in g:
        for filename in filelist:
            if filename.endswith('.c'):
                files.append(filename)
    return files

6)window窗口,当命令行含有-x的时候,调用此窗口,选择文件进行统计。

def Window():
    """打开窗口,选择文件"""
    root = tk.Tk()
    root.title("选择文件")
    root.geometry("300x100")
    button = tk.Button(root, text='浏览文件', relief=tk.RAISED,command=Response)
    button.place(x=100, y=20, width=100, height=50)
    root.mainloop()
    sys.exit()

7)Response()函数,当点击浏览文件按钮后,弹出文件管理窗口,选择文件。

def Response():
    '''打开选择文件夹对话框'''
    root = tk.Tk()
    root.withdraw()

    Filepath = filedialog.askopenfilename() #获得选择好的文件
    # print('Folderpath:',Folderpath)
    print('Filepath:',Filepath)
    data_list = out.count(Filepath)
    print(data_list)
    Result(data_list,Filepath)

8)Result()函数,利用tkinter的窗口显示结果,现学现做,略显生硬。

def Result(datas,filename):
"""统计结果窗口"""
root = tk.Tk()
root.title("选择文件")
root.geometry("420x320")

file_name = tk.Label(root, text='文件名: %s'%filename, justify=tk.RIGHT, width=80)
line = tk.Label(root, text='行数: %s'%datas['line'], justify=tk.RIGHT, width=80)
word = tk.Label(root, text='单词数: %s'%datas['word'], justify=tk.RIGHT, width=80)
character = tk.Label(root, text='字符数: %s' % datas['character'], justify=tk.RIGHT, width=80)
empty_line = tk.Label(root, text='空行数: %s' % datas['empty_line'], justify=tk.RIGHT, width=80)
note_line = tk.Label(root, text='注释行: %s' % datas['note_line'], justify=tk.RIGHT, width=80)
code_line = tk.Label(root, text='代码行: %s' % datas['code_line'], justify=tk.RIGHT, width=80)

file_name.place(x=50,y=10,width=280,height=30)
line.place(x=135, y=40, width=100, height=20)
word.place(x=135, y=85, width=100, height=20)
character.place(x=135, y=130, width=100, height=20)
empty_line.place(x=135, y=175, width=100, height=20)
note_line.place(x=135, y=220, width=100, height=20)
code_line.place(x=135, y=265, width=100, height=20)

root.mainloop()
sys.exit()

6. 测试运行

测试文件:

测试结果:

7. 实现完程序后,实际花费时间

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 30 
Estimate 估计这个任务需要多少时间 30 50 
Development 开发 800 1000
Analysis 需求分析(包括学习新技术) 60 120 
Design Spec 生成设计文档 20 20 
Design Review 设计复审    
Coding Standard 代码规范 20 20 
Design 具体设计 30 30 
Coding 具体编码 300 400 
Code Review 代码复审 20 30 
Test 测试(自我测试、修改代码、提交修改) 200 200 
Reporting 报告 60 60 
Test Report 测试报告 30 30 
Size Measurement 计算工作量 10 10 
Postmortem&Process Improvement Plan 事后总结,并提出过程改进计划 30 30 
Total 合计  1610  2030

8. 项目小结

经过这个小项目开发,发现的问题还是挺多的,编程基础很重要,有很多功能函数其实已经存在的了,只是不知道,或者不会调用,然后自己编码进行解决,吃力不讨好的事情,费时间,而且代码拓展性不高。有些功能看起来很难实现,但细细分析,把程序分为一个个函数,把每个函数的功能写好,再供程序调用,先解决小的问题,把简单的弄好,困难的部分也会变得简单。由于时间和基础的关系,有些功能没完全实现,或者是没实现,所以说PSP表格很重要,对自己的时间规划进行预估,给自己压力,每一次缩小了实际耗时和预估耗时的差距,就是进步。此次作业存在许多不足,以后会加强改进。

2020-03-15 23:57:00

原文地址:https://www.cnblogs.com/frspring/p/12496778.html