第四次作业-单词统计器
项目地址link
PSP表格
计算模块接口的设计与实现过程
类的定义如下
class TextQuery
{
friend ostream& operator<<(ostream& os, TextQuery& item);
public:
TextQuery(const string&);
TextQuery() = default;
bool open(const string&);
auto size() const { return allwords.size(); }//返回单词数
auto line() const { return line_no; }//返回段落数
auto charsize() const { return char_size; }//返回字符数
void setprintsize(int _size)//设定输出的单词数
{
printsize=_size;
}
void countwords(int n);//统计词组的操作函数
void printscreen(ostream& os);
void printfile(ofstream& os);
private:
vector<string> file;
map<string, size_t> word_count;
vector < std::pair< string, size_t> >words_sorted;
int line_no = 0;
int char_size = 0;
int printsize = 10;
map<string, size_t> vec;
void datapcs();
vector<string> allwords;
};
我们可以看见这里有一个类TextQuery,构造函数接受一个字符串作为地址,或者使用成员函数open(),其他几个函数都已在注释中说明。保存数据的容器等在privte中。特别的printscreen和printfile两个函数接受流输出到屏幕和文件,其实内部实现编码都是一样的,本来想用模板成员函数来实现,但定义在外面会出现链接错误,只能写成两个函数。
最关键的算法
如何统计词频呢?我们定义了一个map<string, size_t>,其中的每一对元素pair包含一个key作为词名,以及一个vulue为其频数。用getline对一整段进行读取,然后保存在一个string里面,再将其绑定到一个字符串流istringstream,循环读取这个istringstream,因为其遇到空格停止读入,所以读取到的全是单个的单词或标点符。将读取到的单词保存到map里面作自增运算,这样遇到重复的单词其vulue就会+1。
mian函数的其他参数不固定顺序,但-i 必须是第一个参数(总要读取个文本)运行结果如下图,参数为-i 123.txt -o 833.txt -n 10 -m 3
代码复审过程
实现其大体功能后,在对新增功能进行设计时发型之前的设计不能很好的支持后续新增的功能,只能重构。费时费事。
计算模块接口部分的性能改进
如图所示,消耗最大的显然是词组计数函数,该函数存在多个拷贝赋值的循环,但这是没办法的事情,能改进的已经改了。
计算模块部分单元测试展示
部分测试代码如下
TEST_METHOD(Testsize1)
{
TextQuery txt;
txt.open("test.txt");
vector<string>::size_type i=3;
Assert::AreEqual(i, txt.size());
}
测试函数容器大小返回值是否与提供的测试文本相符合
测试结果如下
计算模块部分异常处理说明
ifstream is(str);
try
{
if (!is)
{
throw std::runtime_error("File path error");
}
}
catch (std::runtime_error err)
{
std::cout << err.what() << endl;
exit(1);
}
如上所述,try语句块和异常处理,try语句块对应一个catch字句,该字句负责处理类型为runtime_error的异常。如果try语句块的代码抛出了runtime_error的异常,接下来执行catch块内的语句。提示信息中输出了err.what()的返回值,what是runtime_error的一个成员函数,返回初始化时所用的string对象的副本。
测试结果如下