您的位置:首页 > 编程语言 > C语言/C++

c++primer关联容器中的“单词转换map程序”分析

2017-06-30 20:17 831 查看
     c++primer第五版的第11章关联容器部分的结尾是一个map单词转换程序和无序容器,其中map单词转换程序书上讲了很多,这里只是对书上讲的内容进行补充,更好的理解这个程序。

在书上程序的基础上,我对其稍微进行了改动。其中transform函数我新添了一个形参:ofstream&output,用来将转换后的内容写进一个记事本文档中,因此对transform的函数定义也进行了小小的修改。此外,本程序是在VS2013S上运行的,在项目下有头文件transform_map.h和源文件transform_map.cpp。头文件中包含了必须的引用头文件和对三个函数的声明,源文件中包含了必须的引用头文件、三个函数的定义及main函数。下面是程序代码。

头文件transform_map.h

#include <iostream>
#include <string>
#include <vector>
#include<map>
#include<fstream>
#include<sstream>

using namespace::std;
void word_transform(ifstream&map_file, ifstream&input, ofstream&output);
map<string, string>buildMap(ifstream&map_file);
const string& transform(const string& s, const map<string, string>& m);


源文件transform_map.cpp

#include <iostream>
#include <string>
#include <vector>
#include<map>
#include<fstream>
#include<sstream>
#include<transform_map.h>

using namespace::std;

/*transform函数,输入依次为映射关系文件、输入文件和输出文件
调用buildMap函数和transform函数*/
void word_transform(ifstream&map_file, ifstream&input, ofstream&output)
{
auto trans_map = buildMap(map_file);
string text;
while (getline(input, text))
{
istringstream stream(text);
string word;
bool firstword = true;
while (stream >> word)
{
if (firstword)
{
firstword = false;
cout << transform(word, trans_map);
output << transform(word, trans_map);
}
else
{
cout <<" "<<transform(word, trans_map);
output << " ";
output << transform(word, trans_map);
}
}
cout << endl;
output << endl;
}
}
/*buildMap函数,输入为映射关系文件
从映射关系文件提取映射关系,返回一个map,map的第一个成员函数为拟替换的字符串,第二个成员函数为
拟替换字符串对应的替换后的字符串*/
map<string, string>buildMap(ifstream&map_file)
{
map<string, string>trans_map;
string key;
string value;
while (map_file >> key&&getline(map_file, value))
{
if (value.size() > 1)
trans_map[key] = value.substr(1);
else
throw runtime_error("No rule for" + key);
}
return trans_map;
}
/*transform函数,输入依次为待转换的字符串和一个map型的映射关系表,返回一个const string&的字符串
transform函数是进行底层实际转换工作的*/
const string& transform(const string& s, const map<string, string>& m)
{
auto map_it = m.find(s);
if (map_it != m.cend())
return map_it->second;
else
return s;
}
//主函数
int main()
{
ifstream input("E:\input.txt");
ifstream map_file("E:\map_file.txt");
ofstream output("E:\output.txt");
word_transform(map_file, input, output);
system("pause");
return 0;
}


main函数中的input.txt如下图:



main函数中的mapfile如下图所示:



main函数中最后得到的的output.txt如下图所示:



下面对程序进行分析:

书上对程序已经分析了很多,这里主要记录一下当时自己不清楚的地方。

首先是一些基本概念:

1、cin/ifstream和getline

      用cin或者ifstream这类流读取数据时,以空白字符(包括空格、回车键、tab键)作为终止标志,只要读到了这些字符流的读取就停止;而getline是针对string的,且读取行的时候是可以接收空格字符的。

2、输入流的字符指针

        输入流中的字符指针,指向当前应访问的字符。在开始时,指针指向第一个字符,在后面的读取中,指针因读取的进行而依次向后移动。当输入流遇到终止标志而停止时,读取操作是停止了,但输入流中的字符指针还会随着下一次读取而从上一次读取停止的地方开始继续向后移动。详细的我用程序来说明。

介绍完一些概念后,我对程序中的一些小细节进行说明。

1、word_transform函数

     “getline(input, text)”,将输入文件的每一行给了string型的text,稍后又用istringstream型的输入流与之关联,对stream操作就是对input文件中的每一行操作。下面的while (stream >> word)这句将input的每一行的每个单词逐一给word。举个例子,比如text的内容是"where r u",输入流的字符指针指向where,把where给word,随后进行firstword判断,firstword的初始值是true,因此执行首个单词的操作,调用后面定义的transform函数,然后输入流的字符指针指向where后面的空格,此时输入流终止输入,进入到下一个while的循环步。下一个while的循环步中,输入流的字符指针向前移动一步,即where后面的空格的下一位,即r,之后输入流的字符指针继续向前移动,指向r后面的空格,则stream终止此循环步的输入操作,把r给word,进行transform函数的调用,然后再通过外面的while循环进入到下一个循环步。在下一个循环步中,字符指针继续向前移动,指向u,再重复上面的操作,实现把where
r u三个字符串通过输入流去掉空格后分别给word。

2、buildMap函数

       函数中“while (map_file >> key&&getline(map_file, value))”有点不太好理解。举个例子,比如map_file的第一行是“y why”.首先文件的输入字符指针指向第一个y,随后向前移动指向y后面的空格,停止读入,此时把y给了key。注意这里跟上面的输入流不一样,下面的getline操作是跟第一个读入操作是在一个循环步内的,此时输入流的字符指针还是指向的y后面的空格,因此接下来的getline函数是把y后面的空格和why一起整行读给了value。接着调用string特有的substr函数将第一个空格跳过,因此substr内的参数是1(从1这个标号的元素开始)。这样就实现了把关键字和对应的值分开,且跳过中间的空格对应赋值的操作。

3、transform函数

       这里主要说明一下find函数,跟string的find函数不同,map的find()函数接收的形参是一个关键字key,如果key在map中,则返回指向key对应的pair元素的迭代器(注意是pair元素而不是key对应的value),否则返回map.end()。

      主函数中将三个输入输出流跟电脑里的txt文件相关联后,执行第一个函数即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: