天天看點

福大軟工1816 · 第二次作業 - 個人項目

福大軟工1816 · 第二次作業 - 個人項目

一、Github項目位址

Github項目位址

二、PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 20
· Estimate · 估計這個任務需要多少時間
Development 開發 670 1120
· Analysis · 需求分析 (包括學習新技術) 120 300
· Design Spec · 生成設計文檔 15
· Design Review · 設計複審
· Coding Standard · 代碼規範 (為目前的開發制定合适的規範) 30
· Design · 具體設計 40
· Coding · 具體編碼 360
· Code Review · 代碼複審 50 60
· Test · 測試(自我測試,修改代碼,送出修改)
Reporting 報告 100
· Test Repor · 測試報告
· Size Measurement · 計算工作量
· Postmortem & Process Improvement Plan · 事後總結, 并提出過程改進計劃 80
|       | 	合計  |790 |1260|
           

三、解題思路描述

解題思路描述。即剛開始拿到題目後,如何思考,如何找資料的過程。

1、首先,題目要求在程式中對指定檔案進行讀寫操作,并且輸入檔案名以指令行參數傳入。之前有稍微接觸過檔案讀寫和指令行傳參的相關内容,是以對這部分的要求并未太過糾結。

2、題目的具體要求是統計檔案的字元數、有效行數、合法單詞數,并字典序輸出詞頻最高的10個合法單詞。

  • 統計檔案的字元數。可以從檔案中依次讀取字元,通過判斷讀取到的字元是否為ASCII碼進行字元統計。
  • 統計檔案的有效行數。題目要求“任何包含非空白字元的行,都需要統計。”我的了解是如果一行中隻包含空格或制表符,則将其視為空白行,不予統計。可以用getline()函數從檔案中逐行讀取,去除行中的空格和制表符,如果處理後的字元串的長度仍大于0,則将其視為有效行。思路參考部落格1。
  • 統計檔案中的合法單詞數,并字典序輸出詞頻最高的10個合法單詞。考慮這個功能的實作花費了我最多的時間和精力。題目對單詞的形式提出了要求,即“單詞:至少以4個英文字母開頭,跟上字母數字元号,單詞以分隔符分割,不區分大小寫。”另外,題目中提到了單詞的分隔符是非字母數字元号,是以就不能簡單的根據空格提取單詞,提取單詞的過程中還要進行對單詞格式的檢查。是以,我用邏輯判斷截取合法單詞,用map進行詞頻統計,最後借助vector輸出詞頻最高的10個合法單詞。思路和實作參考部落格2。

四、設計實作過程

設計實作過程。設計包括代碼如何組織,比如會有幾個類,幾個函數,他們之間關系如何,關鍵函數是否需要畫出流程圖?單元測試是怎麼設計的?

1、代碼組織

我把程式的主要功能:統計字元數、統計有效行、統計合法單詞數和按字典序輸出詞頻最高的10個合法單詞封裝成了一個Statistics類,沒有将檔案的操作單獨封裝成類,在主函數中進行檔案的打開和關閉,将檔案參數傳給類中的統計功能函數,實作統計功能。關系如下:

福大軟工1816 · 第二次作業 - 個人項目

2、關鍵函數流程圖

int words(ifstream& in)統計單詞數及詞頻流程圖:

補充:在i=str.length()-1時,情況1:str[i]為字母,此時若flag>=3,截取合法單詞;情況2:str[i]為數字,此時若flag>=4,截取合法單詞;情況三:str[i]為非數字字母字元,無特殊處理。

補充2:在進行截取前,如果所標明截取部分的前一個字元為數字,判斷為不合法單詞,放棄截取。

3、單元測試

我在這一步折騰了很久,先是找資料學習如何進行單元測試,之後在實踐中也遇到了很多的問題,特别是沒有把測試用的文檔放在正确的地方導緻測試結果老是失敗。

為了更友善地進行單元測試,我對原先程式的封裝進行了改動,實施了單元測試之後切實感受到了它的好處,利用單元測試可以很好的檢測程式中的功能,我在進行單元測試的過程中就找到了我程式中的幾個bug,如果将來要進行大的項目的建設,單元測試帶來的友善應該會更加顯著。

我設計的單元測試有:回車字元的統計、字元數的統計、有效行數的統計、單詞數的統計、合法單詞的提取、是否轉換為小寫字母、詞頻統計是否正确、單詞是否按字典序排列、空文檔的統計、僅含空格、制表符、回車的文檔的統計。

單元測試部分代碼:

namespace UnitTest4//測試單詞數的計算
{
	TEST_CLASS(UnitTest1)
	{
	public:

		TEST_METHOD(TestMethod1)
		{
			ifstream in;
			in.open("test4.txt", ios::in);
			Statistics s;
			Assert::IsTrue(s.words(in) == 3);
		}
	};
}
           

單元測試結果如下:

福大軟工1816 · 第二次作業 - 個人項目

單元測試得到的測試覆寫率截圖:

福大軟工1816 · 第二次作業 - 個人項目

主函數裡未被覆寫部分為錯誤處理代碼。

五、性能分析和改進

記錄在改程序式性能上所花費的時間,描述你改進的思路,并展示一張性能分析圖(由VS2017的性能分析工具自動生成),并展示你程式中消耗最大的函數。

選擇33.6M的txt文檔進行性能分析。

性能分析圖:

福大軟工1816 · 第二次作業 - 個人項目

消耗最大的函數:

福大軟工1816 · 第二次作業 - 個人項目

消耗最大的函數是Statistics類裡統計單詞數及詞頻的函數words(),其中,消耗主要在對map的操作以及檔案的讀取上。

六、代碼說明

展示出項目關鍵代碼,并解釋思路與注釋說明。

1、統計行數

去除一行中的空格和制表符,如果該行長度仍大于0,說明其為有效行數。

主要代碼:

while (getline(in, str))
	{
		str.erase(std::remove(str.begin(), str.end(), ' '), str.end());//删除一行中的空格
		str.erase(std::remove(str.begin(), str.end(), '\t'), str.end());//删除一行中的制表符
		if (str.length() > 0) //如果删除制表符和空格之後的一行資料還有其他字元就算有效行
		{

			line++;
		}
	}
           

2、按字典序輸出詞頻最高的10個單詞

借助vector輸出:将儲存于map中的各單詞的詞頻導入vector,接着對vector從大到小排序,最後将vector中排在前十的數字依次與map中記錄的詞頻比對,輸出最先比對到的單詞和詞頻,置輸出的單詞的詞頻為0。

map<string, int>::iterator it;
	for (it = word.begin(); it != word.end(); it++)
	{
		int t = (*it).second;
		a.push_back(t);
	}
	sort(a.begin(), a.end(), cmp);
	if (wnum == 0)
	{
		out << "該文檔不存在合法單詞!" << endl;
	}
	else
	{
		for (int i = 0; i < wnum && i < 10; i++)
		{

			int t = a[i];
			for (it = word.begin(); it != word.end(); it++)
			{
				if ((*it).second == t)
				{
					out << "<" << (*it).first << "> :" << t << endl;
					(*it).second = 0;
					break;
				}
			}
		}
	}
           

3、錯誤處理部分

處理指令行輸入參數錯誤

if (argc != 2)//檢測輸入的指令行參數是否正确
{
	cout << "輸入參數錯誤!" << endl;
	exit(1);
}
           

處理輸入輸出檔案打開失敗

infile.open(argv[1], ios::in);
	if (infile.fail())
	{
		cout << "輸入檔案打開失敗!" << endl;
		exit(1);
	}
	outfile.open("result.txt", ios::out);
	if (outfile.fail())
	{
		cout << "輸出檔案打開失敗!" << endl;
		exit(1);
	}
           

七、心路曆程與收獲

結合在建構之法中學習到的相關内容與個人項目的實踐經曆,撰寫解決項目的心路曆程與收獲。

這次的作業花費了我很多的時間和精力,我的能力比我想象中的還要不足,作業中列出了一項項具體的要求,是以我在實踐中就按照這一項項要求去思考、搜尋、學習,在搜尋過程中我找到了很多比我原先想的要友善得多的解決方法,見識了很多新知識和新技術,可以說,我在這次個人項目裡做的最多的就是學習,學習新知識,比如軟工的流程和規範、字元串處理、STL的應用,學習新技術,比如vs的單元測試、性能分析等等,這些新知識和新技術算是我這次最大的收獲了吧。另外,寫部落格一直是很讓我頭疼的一件事,我在寫部落格上也花費了相當多的時間和精力,怎麼在部落格中清楚地表達自己的想法和經曆,展現自己的成果和收獲是一個很重要的能力,我在這方面有很大的欠缺,有待加強,希望以後寫部落格能成為一項我喜歡的事。

參考資料:

部落格1:https://blog.csdn.net/haomingzidoumeilea/article/details/8977012

部落格2:https://blog.csdn.net/hisfox/article/details/80013414#t3