2017秋-軟件工程第二次作業
本周因為個人緣故,參加社團活動作業沒能及時完成。對此我表示,做過就不後悔,至少我覺得生活是豐富多彩的,錯過的時間就應該努力趕上!夜深人靜的時候總是可以讓人反省自己。本次作業我只實現了第一個功能和第二個功能的部分。對此我表示很不滿,但是時間緊迫、個人能力有限,以至於自己沒能讓自己的軟件看起來完美。
第二次作業的內容非常有趣,這也是我一直想做的一件事情,統計一篇文章裏的字詞。我知道自己的編程能力較差、距離完成提交時間很近,自己手寫全部是不能及時按照約定提交的,於是就嘗試借鑒前人的代碼。第一晚的努力各種報錯的沖擊下化為無用功,因為第一晚所修改的代碼不可讀取大文件。我對其中一些語句的理解還有所不足,所以第二天就沒再使用。第二天我從51網站上下載了一份有關“詞頻統計”功能的代碼來使用。老師提到希望我們使用c#語言,因為前一周及周末都沒有花時間學習,對新鮮語言感到陌生和抗拒,又因為不想安裝jave環境,所以只好選用c++來開發。第一晚安裝了visualstadio,新建項目運行代碼。
任務一,主要有2部分:1讀取示例文本文件中的文字,2對該文本中的文字進行數量統計。但是我覺得本部分難點在於如何在控制臺,使用命令行語句,操作程序。先上圖,查看完成結果。
因為在命令行執行,這個是我不熟悉的地方。開始的時候我是不明白的。包括那個“type”的功能也不知道。第一項比較簡單。
第二項作業我遇到了很多難題:包括自己手打的txt就出錯,老師示例樣本中的卻不出錯(開始的時候我沒有下載到老師的測試用例,而是復制全部拷貝)、我還修改了txt的字符格式。大文件的讀取也是一個問題,在第一晚嘗試的程序中不能很好的讀取全部內容(所以舍棄不用),之後就是一些小問題,我一一解決。如下展示部分關鍵代碼。
該部分代碼用於顯示輸出內容,格式控制的主要部分。
1 void Display_for_softwareclass(list<Word> &lWord) 2 { 3 list<Word>::iterator iteBegin = lWord.begin(); 4 list<Word>::iterator iteEnd = lWord.end(); 5 list<string> word; 6 for (; iteBegin != iteEnd; iteBegin++) 7 { 8word.push_back((*iteBegin).GetWordInfor()); 9 } 10 word.sort(); 11 word.reverse(); 12 int icount = 0; 13 string sTemp; 14 list<string>::iterator wordBegin = word.begin(); 15 list<string>::iterator wordEnd = word.end(); 16 sTemp = *wordBegin; 17 int total = 1;//用於記錄不同的單詞的數目 18 19 for (; wordBegin != wordEnd; wordBegin++) 20 { 21 if (sTemp == *wordBegin) 22 { 23 icount++; 24 continue; 25 } 26 total++; 27 if (sTemp != *wordBegin) 28 { 29 sTemp = *wordBegin; 30 icount = 1; 31 } 32 } 33 cout <<"total "<< total << endl << endl; 34 word.sort(); 35 word.reverse(); 36 icount = 0; 37 wordBegin = word.begin(); 38 sTemp = *wordBegin; 39 40 cout << left << setw(15) << sTemp; 41 for (; wordBegin != wordEnd; wordBegin++) 42 { 43 if (sTemp == *wordBegin) 44 { 45 icount++; 46 continue; 47 } 48 cout << right << setw(3) << icount << endl; 49 //total++; 50 if (sTemp != *wordBegin) 51 { 52 sTemp = *wordBegin; 53 cout << left << setw(15) << sTemp ; 54 icount = 1; 55 } 56 } 57 cout<< right << setw(3) << icount << endl; 58 cout << endl << endl; 59}
這段代碼展示的是消耗我時間最長的一部分代碼。其中主要的問題來自數據類型!!!目前來講,通過命令行控制程序這個功能我知道怎麽實現,但在本程序中沒有體現。
1 /* 2 inline char* UnicodeToAnsi(const wchar_t* szStr) 3 { 4 int nLen = WideCharToMultiByte(CP_ACP, 0, szStr, -1, NULL, 0, NULL, NULL); 5 if (nLen == 0) 6 { 7 return NULL; 8 } 9 char* pResult = new char[nLen]; 10 WideCharToMultiByte(CP_ACP, 0, szStr, -1, pResult, nLen, NULL, NULL); 11 return pResult; 12 } 13 char TcharToChar(const TCHAR * tchar) 14 { 15 int iLength; 16 char res; 17 char * _char; 18 //獲取字節長度 19 iLength = WideCharToMultiByte(CP_ACP, 0, tchar, -1, NULL, 0, NULL, NULL); 20 //將tchar值賦給_char 21 res = WideCharToMultiByte(CP_ACP, 0, tchar, -1, _char, iLength, NULL, NULL); 22 return res; 23 } 24 */ 25 int _tmain(int argc, _TCHAR* argv[]) 26 { 27 list<Word> lWord; 28 string fileName; 29 cout << ">wf -s "; //這兩行完全是為了湊格式寫的 30 cin >> fileName; 31 OpenFile(fileName, lWord); 32 Display_for_softwareclass(lWord); 33 /* 34 wcout << argc << endl; 35 for (int i = 0; i < argc; i++) 36 { 37 wcout << "argv[" << i << "]=" << argv[i] << endl; 38 } 39 char argv_char[100] = ""; 40 char argv_char_result[100] = ""; 41 argv_char_result[100] = TcharToChar(argv[2]); 42 string fileName; 43 fileName = argv_char_result[100]; 44 cout << "文件名字是:"<<fileName; 45 OpenFile(fileName, lWord); 46 Display_for_softwareclass(lWord); 47 */ 48 return 0; 49 }
在命令行中,運行“wf”文件,傳遞的第一個參數是“-s”,第二個參數是“test.txt”。“-s”是參數?還是什麽?使用不同語言的同學給了我各種各樣的回答,簡單說幾個:某個參數的形參、無意義的參數,空過去不用就好、也許是運行程序中預期的某種功能s,lunix系統下的某種用法。至此,我想聽一下老師的解答。其實不是我“不想問”,而是我“不會問”。我不知道怎麽描述這個問題,不知道這個是有關那一部分的知識,怎麽提問。
在一段時間的學習後,我大概知道了其中的含義,在使用控制臺運行時,main()函數是可以接收參數的!它不僅僅是一個函數的名稱了。開始的時候我是高興的,因為通過嘗試小例子,我可以愉快的讀寫main()函數中傳入的參數。但是當具體寫入我的程序的時候,我就很麻煩:各種錯誤。最大的問題來自這裏:
int _tmain(int argc, _TCHAR* argv[]){}
_tmain和main的區別,char和_TCHAR*的區別?我希望使用_TCHAR* 這樣的數據類型的字符,將它轉化為string類型的即可當作文件名使用,但是強制轉換過程中出現了問題。我還嘗試使用main和char代替他們,也出現了問題。出現的問題對我來說,無法理解,感覺不好解決,經過百度,我得到了很多目前我覺得很鬧心的答案,好幾次出現“類似的”問題,但是百度得到的答案卻不同:內存出錯、內存沖突、空指針、內存空間不足、叫我們調用堆棧查看內部獲取值。我也看到了獲取了非法的數值,應該出現1個單詞的地方出現了一行,但是我卻不知道怎麽找到對應解決辦法。
如下,我想問老師一些問題:
1我們是應該先仔細看別人的代碼,再模仿寫自己?還是從頭開始寫自己的,不會哪裏找哪裏?
2遇到那些,不知道怎麽解決的問題怎麽問?我們應該怎樣描述所遇到的問題?去哪裏問?我們怎樣較快的查找到相關的解答?
3抄襲可恥,但是復制代碼屬於抄襲麽?怎麽算這個軟件是我自己寫的,還是抄別人的?
4怎樣看待那些莫名其妙的問題?比如自己手寫輸入的測試用例就不好用,反而下載的好用?那我怎麽確定是樣本不好,還是我的程序不好呢?
任務一小結:完成了讀取文本文件內容並輸出的功能,完成了對一些符號的識別和區分。未完成大小寫的統一、未完成從命令臺輸入指令傳遞參數的功能。
任務二
任務二是任務一的升級,要求讀入大量的數據並統計單詞量。我完成了統計每個單詞數量、單詞總個數的功能沒有完成排序功能,如下是效果展示圖和代碼。
采用的是《戰爭與和平》大概3.5MB.很多程序不能運行大文件,本程序可以讀取大文件。目前沒有增加給它排序的功能。如下代碼是打開文件讀取數據部分代碼。
void OpenFile(const string fileName,list<Word> &lWord) { //list<Word> lWord; int paragraphNum = 1; int sentenceNum = 1 ; int wordNum = 1; ifstream fin(fileName.c_str()); if(!fin) { cout<<"File open error!\n"; return; } char ch; while(fin.get(ch)) { if(ch==‘\n‘) { paragraphNum++; sentenceNum=1; wordNum=1; } else { char temp[50]; int icount=0; while((ch !=‘\n‘)&&(ch !=‘.‘)&&(ch !=‘!‘)&&(ch !=‘?‘)&&(ch !=‘ ‘)&&(ch !=‘,‘)&&(ch !=‘、‘)) { temp[icount]=ch; icount++; fin.get(ch); } temp[icount]=‘\0‘; if(icount>=1) { lWord.push_back(Word(temp,paragraphNum,sentenceNum,wordNum)); } if((ch==‘.‘)||(ch==‘!‘)||(ch==‘?‘)) { sentenceNum++; wordNum=0; } if((ch==‘ ‘)||(ch==‘;‘)||(ch==‘、‘)) { wordNum++; } } }
總結:
1三號和四號任務沒有完成,其實大部分時間消耗在了學習新知識上面。
2課余活動少參加,現在已經是研究生了,就少玩一點。
3對於以前欠下的債,從現在開始補總比不補強太多。
4會提問才是會學習,我總是沒有周圍的同學會問,他們總能描述清楚想問什麽,而我總是不知道如何張嘴。
5盡量別累計到一起完成任務,不然太多。
軟件PSP分析
時間分析:我覺得可以自己可以接受找到代碼,然後成功運行(而不是全部重寫)這樣的情況。所以自己找到的原始代碼的好壞,或原始版本的好壞就很大程度上影響了進度。哪怕是參考也會有很大影像。如果使用第一晚的,那可能一直都不能使用大文件,而目前的版本中,排序這部分內容就得新添加。但是目前版本又遇到了不可讀參數的問題。我覺得這個軟件只要吧詞語找到,後續的功能越做越快。具體原因呢,就是有些沒有遇到的情況,會花大量的時間去修改。
代碼及版本控制
git地址:https://git.coding.net/Rio56/wf.git
(該版本生成的exe可在根目錄下讀取相應的txt文件。)
2017秋-軟件工程第二次作業