第一次软件工程编程作业
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2020 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167 |
这个作业的目标 | <制作一个程序统计和分析 GitHub 的用户行为数据。> |
学号 | <031802537> |
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | |
Estimate | 估计这个任务需要多少时间 | 10 | |
Development | 开发 | 180 | |
Analysis | 需求分析 (包括学习新技术) | 240 | |
Design Spec | 生成设计文档 | 60 | |
Design Review | 设计复审 | 30 | |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | |
Design | 具体设计 | 60 | |
Coding | 具体编码 | 60 | |
Code Review | 代码复审 | 30 | |
Test | 测试(自我测试,修改代码,提交修改) | 30 | |
Reporting | 报告 | 60 | |
Test Report | 测试报告 | 60 | |
Size Measurement | 计算工作量 | 10 | |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | |
合计 | 980 |
二、前言
第一次浏览完这次作业的时候是懵逼的,原来一个只会c/c++/一丢丢python的小白竟然可以一步登天成长为一个大佬,也可以一周搞定这种完全看不懂的作业吗。然后开始搜这几种信息类型的名字————果然什么也没搜到。。尝试跑一下学长给的测试代码,果然报错了。。只好向有开发经验的大佬和舍友请教,自己再一点一点慢慢学,以下是一些学习过程和网址。
首先学如何读写json文件及json文件转换方法:
https://www.cnblogs.com/XhyTechnologyShare/p/12033690.html
以及with open()as f用法和_init_方法:
https://blog.csdn.net/msspark/article/details/86745391
在Mr.心弦的博客里学到一些python基础
学习正则表达式用于匹配优化:
https://www.runoob.com/python/python-reg-expressions.html
三、设计实现流程
首先设置命令行参数并初始化,输入数据;
递归遍历读取json文件,用json.loads()方法将json数据存入数组;
通过正则表达式匹配数组中的字符串转化为字典格式;
将dict序列化之后用json写文件方法创建3个.json文件将数据存入。
四、具体代码实现
# -*- coding: utf-8 -*-
import os
import argparse
import pickle
import re
Events = ("PushEvent", "IssueCommentEvent", "IssuesEvent", "PullRequestEvent" )
# 四种信息类型
hipping = re.compile(r'"type":"(\w+?)".*?actor.*?"login":"(\S+?)".*?repo.*?"name":"(\S+?)"')
# 使用正则表达式
class inputData:
def __init__(self):
self.User = {}
self.Repo = {}
self.UserRepo = {} # 初始化记录读取的内存
@staticmethod
def parse(file_path: str):
records = [] # 从json文件中逐行抽取信息存入空间
with open(file_path, 'r', encoding='utf-8') as f: # 打开json文件
for line in f:
res = hipping.search(line) # 运用正则表达式匹配有效数据
if res is None or res[1] not in Events:
continue
records.append(res.groups())
return records
def init(self, dirPath: str):
records = []
for curDir, subDir, filenames in os.walk(dirPath):
filenames = filter(lambda r: r.endswith('.json'), filenames)
for name in filenames:
# 将列表扩展拼合
records.extend(self.parse(f'{curDir}/{name}'))
for record in records:
event, user, repo = record
self.User.setdefault(user, {})
self.UserRepo.setdefault(user, {})
self.Repo.setdefault(repo, {})
self.UserRepo[user].setdefault(repo, {})
self.User[user][event] = self.User[user].get(event, 0)+1 # 如果不存在就初始化为0,存在就自身+1
self.Repo[repo][event] = self.Repo[repo].get(event, 0)+1
self.UserRepo[user][repo][event] = self.UserRepo[user][repo].get(event, 0)+1
with open('1.json', 'wb') as f: # 字典转为字符串并将数据写入1、2、3.json
pickle.dump(self.User, f)
with open('2.json', 'wb') as f:
pickle.dump(self.Repo, f)
with open('3.json', 'wb') as f:
pickle.dump(self.UserRepo, f)
def load(self):
if not any((os.path.exists(f'{i}.json') for i in range(1, 3))):
raise RuntimeError('error: data file not found')
with open('1.json', 'rb') as f:
self.User = pickle.load(f)
with open('2.json', 'rb') as f:
self.Repo = pickle.load(f)
with open('3.json', 'rb') as f:
self.UserRepo = pickle.load(f)
def getUser(self, user: str, event: str) -> int:
return self.User.get(user, {}).get(event, 0)
def getRepo(self, repo: str, event: str) -> int:
return self.Repo.get(repo, {}).get(event, 0)
def getUserRepo(self, user: str, repo: str, event: str) -> int:
return self.UserRepo.get(user, {}).get(repo, {}).get(event, 0)
class Run:
# 参数
def __init__(self):
self.parser = argparse.ArgumentParser()
self.data = None
self.argInit()
def argInit(self):
self.parser.add_argument('-i', '--init', type=str)
self.parser.add_argument('-u', '--user', type=str)
self.parser.add_argument('-r', '--repo', type=str)
self.parser.add_argument('-e', '--event', type=str)
def analyse(self):
args = self.parser.parse_args()
self.data = inputData()
if args.init:
self.data.init(args.init)
return 'init done'
self.data.load()
if not args.event:
raise RuntimeError('error: the following arguments are required: -e/--event')
if not args.user and not args.repo:
raise RuntimeError('error: the following arguments are required: -u/--user or -r/--repo')
if args.user and args.repo:
res = self.data.getUserRepo(args.user, args.repo, args.event)
elif args.user:
res = self.data.getUser(args.user, args.event)
else:
res = self.data.getRepo(args.repo, args.event)
return res
if __name__ == '__main__':
a = Run()
print(a.analyse())
五、代码规范规则链接
https://github.com/yezhaoting/software-engineering/blob/master/codestyle.md
六、总结&后记
这次作业对我来说是非常有难度的,以至于单元测试和覆盖率优化都毫无头绪,这让我更加强烈地感受到和dalao们的差距。不过这次作业对于我的代码能力是一次很好的锻炼,对如何成为一个合格的程序员有了一些了解,希望下一次能够圆满地完成任务。