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     {
 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 typedef struct
2 {
3     string danci;//储存单词
4     int count;//记录单词个数,后面出现几次
5 } sq;

排序部分功能如下:

bool compare(sq a, sq b)
{
    return (a.count < b.count);
}
//调用时的语句
    sort(word_count, word_count + total-1 , compare);
    cout << "total    " << total << " words" << endl;
    for (int i = total; i >total-10; i--)
        cout << left << setw(10) << word_count[i].danci << right << setw(5) << ' ' << word_count[i].count << endl;

下图展示为《war and peace》部分章节内容统计。具体因为什么内容报错不可排序全部单词目前还不明确。

 

 

总结:

1三号和四号任务没有完成,其实大部分时间消耗在了学习新知识上面。

2课余活动少参加,现在已经是研究生了,就少玩一点。

3对于以前欠下的债,从现在开始补总比不补强太多。

4会提问才是会学习,我总是没有周围的同学会问,他们总能描述清楚想问什么,而我总是不知道如何张嘴。

5尽量别累计到一起完成任务,不然太多。

 软件PSP分析

时间分析:我觉得可以自己可以接受找到代码,然后成功运行(而不是全部重写)这样的情况。所以自己找到的原始代码的好坏,或原始版本的好坏就很大程度上影响了进度。哪怕是参考也会有很大影像。如果使用第一晚的,那可能一直都不能使用大文件,而目前的版本中,排序这部分内容就得新添加。但是目前版本又遇到了不可读参数的问题。我觉得这个软件只要吧词语找到,后续的功能越做越快。具体原因呢,就是有些没有遇到的情况,会花大量的时间去修改。

 代码及版本控制

 git地址:https://git.coding.net/Rio56/wf.git

(该版本生成的exe可在根目录下读取相应的txt文件。)

 

补交作业部分:第二项任务和第三项任务

第一项任务的完善

这次是真真实实的从命令台中读取了数据,并且进行词汇统计,消除了大小写的问题。

代码如下。因为使用了“int _tmain(int argc, _TCHAR* argv[])”所以消耗了更多的时间。其中我突然想到了“wstring”这种数据格式。让我迅速的完成了从_TCHAR*到wchar,wchar到wstring,再从wstring到string的转换。

感谢高远博同学的帮助,虽然我没使用main(),但是你提示了我很重要的一点:找bug就是找不同。

wchar的使用是上周就遇到的问题,我因为作业中没有用到就没有记录。而这个没有记录的小知识点正是本次解决问题的起始点。这让我知道:每一次错误的尝试都有被记录的资格! 

int _tmain(int argc, _TCHAR* argv[])
{
    //打开某一目录下的txt文件,对其进行读操作
    list<Word> lWord;
    string fileName;
    wstring w_fileName;
 w_fileName = argv[2];
    fileName = WStringToString(w_fileName);
    OpenFile(fileName, lWord);
    Display_for_softwareclass(lWord);
    system("PAUSE");
    return 0;
}

第二项任务的截图:

 

第三项任务截图:

 

 

测试用例中第一篇文章采用网络上一篇英语作文,实现了读取文件夹下所有txt文件,并统计其中词频的工作。

如下粘贴部分有关如何读取文件夹中txt文本文件的代码。这部分代码中,我首先获取文件夹内所有文件名称,再获取文件名后四位的字符,与“.txt”作比较,从而获取txt文件。

 1 void getFiles(string path, vector<string>& files)
 2 {
 3     //文件句柄  
 4     long   hFile = 0;
 5     //文件信息  
 6     struct _finddata_t fileinfo;
 7     string p;//定义了一个字符串
 8     char *q;
 9     string last_4;
10     _finddata_t sFind;
11     long lResult = 0;
12     if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
13     {
14         do
15         {
16             if ((fileinfo.attrib &  _A_SUBDIR))//_A_SUBDIR(文件夹)如果是文件夹的话
17             {
18             //strcmp字符串比较
19             //.表示当前目录   ..表示当前目录的父目录。
20             if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0){
21             getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
22             }
23             else
24             {
25             files.push_back(p.assign(path).append("\\").append(fileinfo.name));
26             }
27             }
28             if ((fileinfo.attrib &  _A_SUBDIR))
29             {
30                 if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
31                     getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
32             }
33             else
34             {
35                 last_4 = substring(fileinfo.name, 4);
36                 if (strcmp(substring(fileinfo.name, 4), ".txt") == 0){
37                     files.push_back(p.assign(path).append("\\").append(fileinfo.name));
38                 }
39             }
40         } while (_findnext(hFile, &fileinfo) == 0);
41 
42         _findclose(hFile);
43     }
44 }

如下代码用于截取后四位字符串。

 1 char *substring(char str[], int n) {
 2     char *strT = (char *)malloc(sizeof(char)* (n + 1));
 3 
 4     int len = strlen(str);
 5     int i;
 6     for (int i = 0; i < n; i++) {
 7         strT[i] = str[len - n + i];
 8     }
 9     strT[4] = '\0';
10     return strT;
11 }

2017-9-26修改:

1完成了重定向功能!

2完成了直接命令行输入功能!

3完成了输入文件名字功能!

如下展示截图和代码情况。

此图展示直接粘贴部分段落统计词语截图

此图展示使用命令行输入“-s war_and_peace.txt”功能,读取文件中内容。(使用我的程序读取文件)

 

 

此图展示“重定向功能”通过“<test.txt”命令行读取test.txt文件中的内容。

 

 

如上,所有功能已经全部实现。感谢高远博同学多次对我的指点与教学 。

发现小的技巧:如果文件路径中包含“空格”会导致程序出现错误。相对路径中存在空格也是不可以的!!!

 

posted @ 2017-09-19 04:56  _Rio56  阅读(693)  评论(5编辑  收藏  举报