软件工程实践个人编程作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2020
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167
这个作业的目标 ①读写json文件并统计数据,以命令行展示 ②养成良好的开发习惯
学号 031802309
使用语言 C++




一、PSP 表格

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

二、解题思路描述

本次作业要求制作一个程序统计和分析 GitHub 的用户行为数据。原始数据以多个 json 对象给出,保存在文件中。我将其命名为 Data.json 。可以分为以下几个部分进行思考:

1.读写 json 文件。确定了 C++ 作为开发语言后,我上网查阅了 C++ 解析 json 的方法,了解到两个库: JsonCpp 和 CJsonObject 。我选择了 JsonCpp 来进行解析。读取原始数据文件,提取所需数据并写入 Temp_Json.json 文件。解析命令行参数,遍历 Temp_Json.json 文件,根据所需参数对数据进行统计。

2.自定义命令行参数。下载 getopt 库,学习 getopt( ) 、getopt_long( ) 等函数的用法。

3.使用Git进行版本控制。

三、设计实现过程

各函数之间的关系如图所示。

四、代码说明

在主函数中设置命令行参数,根据参数解析结果调用不同的函数。

int main(int argc, char** argv) {
	int opt;
	int digit_optind = 0;
	int option_index = 0;
	string user, event, repo;

	char* optstring = "i:u:e:r:";
	static struct option long_options[] = 
	{
		{"init",	  1,	NULL,	'i'},
		{"user",	  1,	NULL,	'u'},
		{"event",	  1,	NULL,	'e'},
		{"repo",	  1,	NULL,	'r'},
		{ 0,		  0,	0,		 0 }
	};

	while ((opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1) {
		switch (opt) {
		case 'i':
			Init(optarg);
			break;
		case 'u':
			user = optarg;
			break;
		case 'e':
			event = optarg;
			break;
		case 'r':
			repo = optarg;
			break;
		}
	}

	if (!user.empty() && !event.empty() && !repo.empty()) {
		Num_User_Event_Repo(user, event, repo);
	}
	if (user.empty() && !event.empty() && !repo.empty()) {
		Num_Event_Repo(event, repo);
	}
	if (!user.empty() && !event.empty() && repo.empty()) {
		Num_User_Event(user, event);
	}

	return 0;
}

初始化函数:Init( );
逐行读取 data.json 文件,提取其中的数据 type 、actor_login repo_name,并将其重新序列化,写入 Temp_Json.json 文件。

void Init(string path) {
	//cout << "进入初始化." << endl;

	int i;
	string str;
	Json::Value value;
	Json::Value value1;
	Json::Reader reader;
	Json::StyledWriter sw;

	ifstream file(path, ios::binary);
	if (!file.is_open()) {
		cout << "Data文件打开失败." << endl;
		return;
	}
	
	i = 0;
	ofstream os;
	os.open("../Data/Temp_Json.json", std::ios::out | std::ios::app);
	if (!os.is_open()) {
		cout << "Temp_Json.json文件创建失败." << endl;
		return;
	}

	os << "[" << endl;
	while (getline(file, str)) {
			i++;
			//cout << i << endl;
			if (reader.parse(str, value)) {
				string type = value["type"].asString();
				string actor_login = value["actor"]["login"].asString();
				string repo_name = value["repo"]["name"].asString();

				value1["id"] = Json::Value(i);
				value1["user"] = Json::Value(actor_login);
				value1["event"] = Json::Value(type);
				value1["repo"] = Json::Value(repo_name);

				os << sw.write(value1);
				os << "," << endl;
				
			}
			else {
				cout << "Data文件读取失败." << endl;
				return;
			}
		}
	os << "]" << endl;
	os.close();
	file.close();
	
	//cout << "初始化完成." << endl;
	return;
}

查询某用户在某项目的某事件数量 :Num_User_Event_Repo( );
Temp_Json.json 中读取 json ,保存在字符串 str 中,对其进行遍历与统计。

void Num_User_Event_Repo(string u, string e, string r) {
	//cout << u << "用户在" << r << "项目的" << e << "事件数量为:" << endl;

	int ret = 0;
	string str, user, event, repo;
	Json::Reader reader;
	Json::Value value;

	ifstream ifile("../Data/Temp_Json.json");
	ostringstream buf;
	char ch;
	while (buf && ifile.get(ch))
		buf.put(ch);
	str = buf.str();
	//cout << str << endl;

	reader.parse(str, value);
	int size = value.size();
	//cout << "size:" << size << endl;
	for (int i = 0; i < size; ++i) {
		user = value[i]["user"].asString();
		event = value[i]["event"].asString();
		repo = value[i]["repo"].asString();
		//cout << user << " " << event << " " << repo << endl;
		if (u == user && e == event && r == repo) {
			ret++;
		}
	}

	cout << ret << endl;
	return;
}

Num_User_Event( ); 和 Num_Event_Repo( ); 与之同理,故不写出。

五、本地测试

命令行运行结果如下:

为了验证我的程序运行结果,我用编辑器查找了一下。如下图,willdollman 有4次匹配,查到的两个 event 都是 PushEvent 。运行结果正确。

六、代码规范链接

点击此处查看详细代码规范

七、困难及总结

VS 编译时报错,显示有无法解析的外部符号,原因是找不到库文件,即 lib 文件。解决方案是用 VS 配置项目属性,在库目录里添加相应库文件所在的目录。

命令行运行时崩溃,并打出错误:JsonCpp Assertion `type_ == nullValue || type_ == objectValue(Jsoncpp 采用 Assert 作为错误处理方法。)原因:读 json 时格式不匹配。我在存数据时是以 [{},{}] 的格式去存的,读的时候应用相匹配的方法去读。解决方案:value后加下标[i]。

遇到的 Bug 和花费的时间都比我预想的要多,不过程序跑起来那一刻还是令人开心的。

原文地址:https://www.cnblogs.com/AJiang0704/p/13655113.html