1. 程式人生 > >2017秋-軟件工程第二次作業

2017秋-軟件工程第二次作業

詞頻 get char* rec 堆棧 空指針 err 不想 做的

本周因為個人緣故,參加社團活動作業沒能及時完成。對此我表示,做過就不後悔,至少我覺得生活是豐富多彩的,錯過的時間就應該努力趕上!夜深人靜的時候總是可以讓人反省自己。本次作業我只實現了第一個功能和第二個功能的部分。對此我表示很不滿,但是時間緊迫、個人能力有限,以至於自己沒能讓自己的軟件看起來完美。

第二次作業的內容非常有趣,這也是我一直想做的一件事情,統計一篇文章裏的字詞。我知道自己的編程能力較差、距離完成提交時間很近,自己手寫全部是不能及時按照約定提交的,於是就嘗試借鑒前人的代碼。第一晚的努力各種報錯的沖擊下化為無用功,因為第一晚所修改的代碼不可讀取大文件。我對其中一些語句的理解還有所不足,所以第二天就沒再使用。第二天我從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     {
 8
word.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秋-軟件工程第二次作業