本周因为个人缘故,参加社团活动作业没能及时完成。对此我表示,做过就不后悔,至少我觉得生活是丰富多彩的,错过的时间就应该努力赶上!夜深人静的时候总是可以让人反省自己。本次作业我只实现了第一个功能和第二个功能的部分。对此我表示很不满,但是时间紧迫、个人能力有限,以至于自己没能让自己的软件看起来完美。
第二次作业的内容非常有趣,这也是我一直想做的一件事情,统计一篇文章里的字词。我知道自己的编程能力较差、距离完成提交时间很近,自己手写全部是不能及时按照约定提交的,于是就尝试借鉴前人的代码。第一晚的努力各种报错的冲击下化为无用功,因为第一晚所修改的代码不可读取大文件。我对其中一些语句的理解还有所不足,所以第二天就没再使用。第二天我从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文件。)