第1次作业

要求0:作业要求地址:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2110

要求1:GIT仓库地址:https://git.coding.net/wudb527/wf.git (master2为中间的过程,V1.0为最终提交的版本,随后对V1.0和主分支master进行了合并)

要求2:PSP阶段表格

SP2.1预估时间600(min)实际开发时间1043(min)
计划2040
·明确需求和其他相关因素,估计每段时间成本2040
开发490903
·需求分析2060
·生成设计文档300
·设计复审(和同学审核设计文档)200
·代码规范(为目前的开发制定合适的规范)1030
·具体设计5060
·具体编码300673
·代码复审2040
·测试(自测、修改代码、提交修改)4040
报告90100
·测试报告3035
·计算工作量3035
·事后总结,并提出过程改进计划3040

 

功能模块具体阶段预计时间(min)实际时间(min)
功能1具体设计1520
具体编码50130
测试完善1012
功能2具体设计1520
具体编码70246
测试完善1513
功能三具体设计2020
具体编码180290
测试完善1515

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分析差距原因:

(1):没有完全按照软件开发的流程来,比如因为感觉是小程序,设计文档就没有做,虽然这一项我没有花时间,但是实际中我却在其他地方饶了弯路。

(2):我对C++的语法没有足够的熟悉,有些数据类型的内置函数不够了解(比如string.c_str()),导致在应用的时候还要上网查询。

(3):在之前没有对题目要求做足够的了解,导致,一边写代码还要返回去看题目要求,花费了不少时间。

要求3

1.解题思路描述

我觉得这个程序的流程大概就是读取文件获得字符串,然后对字符串进行操作获得符合题目要要求的字符,而后进行字符串计数,然后按照题目要求输出就可以了。当第一眼看到这个题目的时候我觉得难点在打开文件、路径输入保存以及进行文件夹下的文件查询,而重点点我觉得有正则表达式的应用。我一开始就打算用C++里STL里面的map容器来实现字符串的计数。但是文件的打开以及文件夹下面的文件读取卡了不少时间,本来打算用C的fopen实现,但是fopen打开文件后获得是字符数组,我打算用string类型保存的单词的,所以还要把字符数组转为字符串,有点繁琐,后来我查找资料知道了C++的文件流,这是一大突破,而在文件夹内部的文件遍历上我查资料知道了 _findfirst()函数可以实现问价的查询。

2.代码解释

难点1:文件的打开

用文件流的话,我们使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里您使用的是 ifstream 或 fstream 对象,而不是 cin 对象。

下面是文件流的使用方法,用于对某一个文件进行读取然后输出。

 1 #include<iostream>
 2 #include<fstream>
 3 using namespace std;
 4 int main()
 5 {
 6     // 以读模式打开文件
 7     ifstream infile;
 8     string path = "D:\\codeblocks\\wf\\input.txt";
 9     //打开文件
10     infile.open(path.c_str());
11     //括号里应该是字符串类型,所以要用到string.c_str()进行转换
12     string str;
13     while(infile>>str)
14     {
15         cout<<str<<endl;
16     }
17     return 0;
18 }

难点2:路径内文件夹的遍历,文件的查找

_findfirst是按照文件名的字典序查找的,所以题目要求的文件名排序问题直接解决了,只要能找到文件那就是符合要求的。

 

这两个函数均在io.h里面。

首先了解一下一个文件结构体:

struct _finddata_t {
    unsigned    attrib;
    time_t      time_create;   
    time_t      time_access;   
    time_t      time_write;
    _fsize_t    size;
    char        name[260];
}; 

time_t,其实就是long

而_fsize_t,就是unsigned long

现在来解释一下结构体的数据成员吧。

attrib,就是所查找文件的属性:_A_ARCH(存档)、_A_HIDDEN(隐藏)、_A_NORMAL(正常)、_A_RDONLY(只读)、_A_SUBDIR(文件夹)、_A_SYSTEM(系统)。

time_create、time_access和time_write分别是创建文件的时间、最后一次访问文件的时间和文件最后被修改的时间。

size:文件大小

name:文件名。

再来看一下_findfirst函数:long _findfirst(const char *, struct _finddata_t *);

第一个参数为文件名,可以用"*.*"来查找所有文件,也可以用"*.cpp"来查找.cpp文件。第二个参数是_finddata_t结构体指针。若查找成功,返回文件句柄,若失败,返回-1。

然后,_findnext函数:int _findnext(long, struct _finddata_t *);

第一个参数为文件句柄,第二个参数同样为_finddata_t结构体指针。若查找成功,返回0,失败返回-1。

最后:_findclose()函数:int _findclose(long);

只有一个参数,文件句柄。若关闭成功返回0,失败返回-1。

资料源自:http://blog.sina.com.cn/s/blog_67e046d10100jwdo.html

下面是小的使用方法:

 1 #include<iostream>
 2 #include<io.h>//_findfirst的头文件
 3 using namespace std;
 4 int main()
 5 {
 6     string path = "D:\\codeblocks\\wf\\";
 7     path += "*.txt";//.txt是文件类型
 8     _finddata_t openfile;
 9     long HANDLE;//_findfirst的返回值,若找到为0,找不到为-1
10     HANDLE = _findfirst( path.c_str(), &openfile );
11     string file_name = openfile.name;//openfile的name成员是找到的文件名
12     cout<<file_name<<endl;
13     return 0;
14 }

 难点3:把一行字符串按照空格分割开来

在这里我想到了stringstream来进行数据流的重定向。下面是我对stringstream的测试:

 

#include<iostream>
#include<sstream>//stringstream的头文件
using namespace std;
int main()
{
    string str = "aaa bbb ccc ddd  eee fff";
    stringstream ss(str);
    string t;
    while(ss>>t)
        cout<<t<<endl;
    return 0;
}

输出为:

可以看到实现了用空格分割字符串。

要点1:由于功能1在输出时要求与输入时的顺序一致,所以我用一个vector<string>依次保存了输入时的字符串。在输出时只要依次取出即可。

 1 vector<string>Vstr;
 2     map<string,int>Map;
 3     int Max_wordsize = 0;
 4     while(ss>>str)
 5     {
 6         if(str[0] >= '0' && str[0] <= '9') continue;
 7         Max_wordsize = Max(Max_wordsize,str.size());//寻找最长单词的长度
 8         if(Map[str] == 0) Vstr.push_back(str);//把每一个单词不重复的保存起来
 9         Map[str]++;
10     }

要点2:功能2在输出时要求字符串按照字典序输出,所以要对vector进行排序,我自定义了cmp函数。

1 bool cmp2(string a, string b)
2 {
3     return a < b;
4 }
sort(Vstr.begin(),Vstr.end(),cmp2);

要点3:在功能3输出时,要求先按照单词数量降序排序,对于数量一致的再按照单词的字典序升序排序,所以我构建了结构体,里面有成员str和num,然后在功能3中把每个结构踢对象存入vector中,然后自定义排序函数。

struct Node
{
    string str;
    int num;
};

 

1 for(int i = 0; i < total;++i)
2         {
3             node.str = Vstr[i];
4             node.num = Map[Vstr[i]];
5             V_node.push_back(node);
6         }
vector<Node>V_node;
/
bool cmp3(Node a, Node b)
{
    if(a.num == b.num) return a.str < b.str;
    return a.num > b.num;
}
/
sort(V_node.begin(),V_node.end(),cmp3);

 

(1)下面是我的完整代码,对功能1,功能2,功能3的判别是根据控制台输入的字符串个数,如果是5段那肯定是功能3,如果不是那就是功能1或功能2,然后查询是有-c还是-f即可判断。

 

  1 #include<iostream>
  2 #include<map>
  3 #include<vector>
  4 #include<sstream>
  5 #include<string>
  6 #include<fstream>
  7 #include<cstring>
  8 #include<cstdio>
  9 #include<cstdlib>
 10 #include<algorithm>
 11 #include<io.h>
 12 using namespace std;
 13 int Max(int a,int b)
 14 {
 15     return a > b ? a : b;
 16 }
 17 int Min(int a,int b)
 18 {
 19     return a < b ? a : b;
 20 }
 21 struct Node
 22 {
 23     string str;
 24     int num;
 25 };
 26 bool Get_FileName(string Path_Name,string &File_Name)
 27 {
 28     struct _finddata_t FileInfo;
 29     long Handle;
 30     Handle = _findfirst((Path_Name+"\\*.txt").c_str(),&FileInfo);//对文件夹下的文件筛选出.txt文件
 31     if(Handle == -1) return 0;
 32     else
 33     {
 34         string temp = FileInfo.name;
 35         File_Name = Path_Name + "\\" + temp;
 36         return true;
 37     }
 38 }
 39 bool cmp2(string a, string b)
 40 {
 41     return a < b;
 42 }
 43 bool cmp3(Node a, Node b)
 44 {
 45     if(a.num == b.num) return a.str < b.str;
 46     return a.num > b.num;
 47 }
 48 void solve(string File_Name,int num)//实际执行文件打开和输出的函数,num = 5为功能2,num= -1 为功能1,num= -2为功能2
 49 {
 50     ifstream infile;
 51     string file_txt = "",str;
 52     infile.open(File_Name.c_str());//打开文件
 53     while(getline(infile,str))
 54     {
 55         file_txt = file_txt + str + ' ';
 56     }
 57     infile.close();
 58     for(string::iterator it = file_txt.begin();it < file_txt.end();it++)//把大写转为小写,并且把非字母数字转为空格
 59     {
 60         if(*it >='A'&&*it<='Z') *it += 32;
 61         else if(*it >='a' && *it <='z') continue;
 62         else if(*it >='0' && *it <='9') continue;
 63         else *it = ' ';
 64     }
 65     stringstream ss(file_txt);
 66     vector<string>Vstr;
 67     map<string,int>Map;
 68     int Max_wordsize = 0;
 69     while(ss>>str)
 70     {
 71         if(str[0] >= '0' && str[0] <= '9') continue;
 72         Max_wordsize = Max(Max_wordsize,str.size());//寻找最长单词的长度
 73         if(Map[str] == 0) Vstr.push_back(str);//把每一个单词不重复的保存起来
 74         Map[str]++;
 75     }
 76     int total = Vstr.size();
 77     if(num == -1)//功能1
 78     {
 79         cout<<"total"<<" "<<total<<endl;
 80         cout<<endl;
 81         for(int i = 0;i < total;i++)
 82         {
 83             cout<<Vstr[i];
 84             int wordsize = Vstr[i].size();
 85             for(int j = 1; j <= Max_wordsize - wordsize;++j) cout<<" ";
 86             cout<<" "<<Map[Vstr[i]]<<endl;
 87         }
 88     }
 89     else if(num == -2)//功能2
 90     {
 91         cout<<"total"<<" "<<total<<" word";
 92         if(total > 1) cout<<'s';
 93         cout<<endl;
 94         sort(Vstr.begin(),Vstr.end(),cmp2);
 95         for(int i = 0;i < total;i++)
 96         {
 97             cout<<Vstr[i];
 98             int wordsize = Vstr[i].size();
 99             for(int j = 1; j <= Max_wordsize - wordsize;++j) cout<<" ";
100             cout<<" "<<Map[Vstr[i]]<<endl;
101         }
102     }
103     else//功能3
104     {
105         Max_wordsize = 0;
106         cout<<"Total word";
107         if(total > 1) cout<<'s';
108         cout<<" is "<<total<<endl;
109         cout<<"----------"<<endl;
110         vector<Node>V_node;
111         Node node;
112         for(int i = 0; i < total;++i)
113         {
114             node.str = Vstr[i];
115             node.num = Map[Vstr[i]];
116             V_node.push_back(node);
117         }
118         sort(V_node.begin(),V_node.end(),cmp3);
119         num = Min(num,total);
120         for(int i = 0; i < num;++i)
121         {
122             Max_wordsize = Max(V_node[i].str.size(),Max_wordsize);
123         }
124         for(int i = 0;i < num;++i)
125         {
126             cout<<V_node[i].str;
127             int wordsize = V_node[i].str.size();
128             for(int j = 1; j <= Max_wordsize - wordsize;++j) cout<<" ";
129             cout<<" "<<V_node[i].num<<endl;
130         }
131     }
132 
133 }
134 int main()
135 {
136     string str_input,Path_Name,File_Name;//控制台输入的内容,实际路径,实际文件名
137     bool havePath = false,haveFile = false;//判断是有路径还是有文件名
138     getline(cin,str_input);
139     vector<string>input;
140     stringstream ss(str_input);//对控制台输入的文字按照空格分割
141     string str;
142     while(ss>>str)
143     {
144         if(str == "-c") haveFile = true;//判断是否有文件名
145         if(str == "-f") havePath = true;//判断是否有判断是否有路径
146         input.push_back(str);
147     }
148     int len = input.size();
149     if(havePath)//如果存在的是路径
150     {
151 
152         for(int i = 0;i < len;i++)
153         {
154             if(input[i] == "-f") {Path_Name = input[i+1];break;}
155         }
156         string temp = "";
157         //因为C++'\'的转义
158         for(string::iterator it = Path_Name.begin();it < Path_Name.end();it++)
159         {
160             if(*it == '\\') temp += "\\";
161             else temp+=*it;
162         }
163         Path_Name = temp;
164         bool is = Get_FileName(Path_Name,File_Name);//获取文件名
165         if(is == false) {cout<<"路径下找不到.txt文件!"<<endl;return 0;}//获取失败,输出
166     }
167     else
168     {
169         for(int i = 0;i < len;i++)
170         {
171             if(input[i] == "-c") {File_Name = input[i+1];break;}
172         }
173     }
174     int num;
175     if(len == 5)
176     {
177         for(int i = 0;i < len ;i++)
178             if(input[i] == "-n")
179             num = atoi(input[i+1].c_str());
180     }
181     else
182     {
183         if(str_input.find("-c") != string::npos) num = -1;
184         else num = -2;
185     }
186     solve(File_Name,num);
187     return 0;
188 }
189 /*
190 wf -f D:\codeblocks\wf
191 wf -f D:\codeblocks\wf -n 3
192 */

 

 

(2)功能测试:注:功能3四种输入均进行了测试

功能1:

功能2:

功能3:

对四种输入均进行了测试,均能实现

 

 

(3)自认为题目中的小细节

1)在输出时单词 word 后面有没有s,我注意到了这个问题,所以我对单词进行了计数,若大于1就加s。

if(total > 1) cout<<'s';

2)对单词数一列的对齐,我用一个变量维护了最大单词长度,然后在输出时对于其他单词,长度比他小几个我就补几个空格,这样就实现了对齐。

1 int Max_wordsize = 0;
2     while(ss>>str)
3     {
4         if(str[0] >= '0' && str[0] <= '9') continue;
5         Max_wordsize = Max(Max_wordsize,str.size());//寻找最长单词的长度
6         if(Map[str] == 0) Vstr.push_back(str);//把每一个单词不重复的保存起来
7         Map[str]++;
8     }

输出时

 1     if(num == -1)//功能1
 2     {
 3         cout<<"total"<<" "<<total<<endl;
 4         cout<<endl;
 5         for(int i = 0;i < total;i++)
 6         {
 7             cout<<Vstr[i];
 8             int wordsize = Vstr[i].size();
 9             for(int j = 1; j <= Max_wordsize - wordsize;++j) cout<<" ";//补充空格
10             cout<<" "<<Map[Vstr[i]]<<endl;
11         }
12     }

(4)对于这次作业我自己的心得:

1)在这次作业的过程中我对自己比较满意的是在正式编码前将 文件打开、指定路径下文件查询、怎样用空格分开字符串,其实在这里面花费时间是最大的,我庆幸我这么做了,如果一开始就正式编码、遇到困难然后去搜寻,那么可能你已经写了很多了,然后如果对新的用法不熟悉,编译会报错,debug会很困难,而我在编码前就通过小实验熟悉了操作,所以在正式编码时debug几乎没有花费多少时间,这算我的一个收获吧!虽然这次我没有犯这个错误但我还是要打好预防针。

2)而不足就是编码前没有足够了解问题,导致频繁去看问题,浪费了不少时间。就构建之法中的软件开发流程而言就不够合格,这次让我意识到麻雀虽小但也五脏俱全,小的软件项目也应该按照流程走,这样表面上花费了时间,但是在总体来看是节省不少时间。

3)GIT并没有那么简单,本以为只要了解了那几个语句就可以了,但是在push是发生了不少错误,查了不少资料才解决。其实C++等语言学习也是一样的,那些语法学习其实是最基础的,然后就是怎样进行组合会什么功能,在升级就是对于各种报错的解决,这一点是没有捷径的,只有长时间的练习才能解决,没有学习是一蹴而就的。

转载于:https://www.cnblogs.com/wudb527/p/9689038.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值