We’ll close this section with a program to illustrate creating, searching, and iterating across a map
. We’ll write a program that, given one string
, transforms it into another. The input to our program is two files. The first file contains rules that we will use to transform the text in the second file. Each rule consists of a word that might be in the input file and a phrase to use in its place. The idea is that whenever the first word appears in the input, we will replace it with the corresponding phrase. The second file contains the text to transform.
If the contents of the word-transformation file are
brb be right back
k okay?
y why
r are
u you
pic picture
thk thanks!
l8r later
and the text we are given to transform is
where r u
y dont u send me a pic
k thk l8r
then the program should generate the following output:
where are you
why dont you send me a picture
okay? thanks! later
Our solution will use three functions. The word_transform
function will manage the overall processing. It will take two ifstream
arguments: The first will be bound to the word-transformation file and the second to the file of text we’re to transform. The buildMap
function will read the file of transformation rules and create a map
from each word to its transformation. The transform
function will take a string
and return the transformation if there is one.
We’ll start by defining the word_transform
function. The important parts are the calls to buildMap
and transform
:
void word_transform(ifstream &map_file, ifstream &input)
{
auto trans_map = buildMap(map_file); // store the transformations
string text; // hold each line from the input
while (getline(input, text)) { // read a line of input
istringstream stream(text); // read each word
string word;
bool firstword = true; // controls whether a space is printed
while (stream >> word) {
if (firstword)
firstword = false;
else
cout << " "; // print a space between words
// transform returns its first argument or its transformation
cout << transform(word, trans_map); // print the output
}
cout << endl; // done with this line of input
}
}
The function starts by calling buildMap
to generate the word-transformation map
. We store the result in trans_map
. The rest of the function processes the input
file. The while
loop uses getline
to read the input file a line at a time. We read by line so that our output will have line breaks at the same position as in the input file. To get the words from each line, we use a nested while
loop that uses an istringstream
(§ 8.3, p. 321) to process each word in the current line.
The inner while
prints the output using the bool firstword
to determine whether to print a space. The call to transform
obtains the word to print. The value returned from transform
is either the original string
in word
or its corresponding transformation from trans_map
.
The buildMap
function reads its given file and builds the transformation map
.
map<string, string> buildMap(ifstream &map_file)
{
map<string, string> trans_map; // holds the transformations
string key; // a word to transform
string value; // phrase to use instead
// read the first word into key and the rest of the line into value
while (map_file >> key && getline(map_file, value))
if (value.size() > 1) // check that there is a transformation
trans_map[key] = value.substr(1); // skip leading space
else
throw runtime_error("no rule for " + key);
return trans_map;
}
Each line in map_file
corresponds to a rule. Each rule is a word followed by a phrase, which might contain multiple words. We use >>
to read the word that we will transform into key
and call getline
to read the rest of the line into value
. Because getline
does not skip leading spaces (§ 3.2.2, p. 87), we need to skip the space between the word and its corresponding rule. Before we store the transformation, we check that we got more than one character. If so, we call substr
(§ 9.5.1, p. 361) to skip the space that separated the transformation phrase from its corresponding word and store that substring in trans_map
,
Note that we use the subscript operator to add the key–value pairs. Implicitly, we are ignoring what should happen if a word appears more than once in our transformation file. If a word does appear multiple times, our loops will put the last corresponding phrase into trans_map
. When the while
concludes, trans_map
contains the data that we need to transform the input.
The transform
function does the actual transformation. Its parameters are references to the string
to transform and to the transformation map
. If the given string
is in the map
, transform
returns the corresponding transformation. If the given string
is not in the map
, transform
returns its argument:
const string &
transform(const string &s, const map<string, string> &m)
{
// the actual map work; this part is the heart of the program
auto map_it = m.find(s);
// if this word is in the transformation map
if (map_it != m.cend())
return map_it->second; // use the replacement word
else
return s; // otherwise return the original unchanged
}
We start by calling find
to determine whether the given string
is in the map
. If it is, then find
returns an iterator to the corresponding element. Otherwise, find
returns the off-the-end iterator. If the element is found, we dereference the iterator, obtaining a pair
that holds the key and value for that element (§ 11.3, p. 428). We return the second
member, which is the transformation to use in place of s
.
Exercise 11.33: Implement your own version of the word-transformation program.
Exercise 11.34: What would happen if we used the subscript operator instead of find
in the transform
function?
Exercise 11.35: In buildMap
, what effect, if any, would there be from rewriting
trans_map[key] = value.substr(1);
as trans_map.insert({key, value.substr(1)})?
Exercise 11.36: Our program does no checking on the validity of either input file. In particular, it assumes that the rules in the transformation file are all sensible. What would happen if a line in that file has a key, one space, and then the end of the line? Predict the behavior and then check it against your version of the program.