In today's exercise, we examine a simple language translation problem: converting a word from English into the children's language Pig-latin. Here are some examples of English words and their Pig-latin translation:
| English | Pig-latin | English | Pig-latin |
|---|---|---|---|
| alphabet | alphabetyay | nerd | erdnay |
| billygoat | illygoatbay | orthodox | orthodoxyay |
| crazy | azycray | prickly | icklypray |
| dripping | ippingdray | quasimodo | asimodoquay |
| eligible | eligibleyay | rhythm | ythmrhay |
| farm | armfay | spry | yspray |
| ghost | ostghay | three | eethray |
| happy | appyhay | ugly | uglyyay |
| illegal | illegalyay | vigilant | igilantvay |
| jury | uryjay | wretched | etchedwray |
| killjoy | illjoykay | xerxes | erxesxay |
| limit | imitlay | yellow | ellowyay |
| messy | essymay | zippy | ippyzay |
Study the examples given, looking for a "rule" that you can use to translate a word from English into Pig-latin. When you think you have found one, record it and then continue.
Today's problem is to complete a program to translate sentences from English into Pig-latin. To do so, we will use a new data type named string. A declaration of the form:
string englishWord = "farm";builds the object englishWord as an indexed variable capable of storing multiple characters:
The numbers 0, 1, 2 and 3 are the index values of the characters within englishWord, and can be used to access the individual characters within the string object.
To begin today's exercise, create a pigLatin project/folder in which to save today's work. Then save a copy of translate.cpp in your new pigLatin folder, and open it from within Visual C++, and use the menu choice
Project -> Add To Project -> Files...to add translate.cpp to your pigLatin project. This file contains the skeleton of a program for translating a sentence from English into Pig-latin. Take a few moments to familiarize yourself with its contents.
Within translate.cpp, we can see several points of interest:
string englishWord,
piglatinWord;
cin >> englishWord;
The >> operator skips leading white space,
reads characters into the string object,
and stops when it encounters more white space.
The effect of operator >> is thus to
read the next word of input into the string object.
cout << piglatinWord;
piglatinWord = Piglatin(englishWord);
cin.get(separator);
Since this call occurs after a string value has been read,
separator will at the end of this call contain whatever
white space character caused the extraction operator to stop.
As usual, we begin by applying object-centered design to our problem.
Function Behavior, Part I. If we ignore the cases where the vowel is the first character in a word, we might describe the behavior of a function to translate an English word into Pig-latin as follows:
Receive an English word. Find the position of the first vowel in that word, checking that a vowel was actually present. (If not, our program should display a diagnostic and terminate.) The Pig-latin word is the portion of the word from the first vowel to its end, followed by the consonants at the beginning of the word, followed by "ay". Return the Pig-latin word.Note that in trying to anticipate what might go wrong, a user might enter a word with no vowels, and so we should check for this possibility.
Function Objects. From this description, we can identify the following objects:
| Description | Type | Kind | Movement | Name |
|---|---|---|---|---|
| The English word | string | varying | received | englishWord |
| Position of the first vowel | int | varying | local | vowelPosition |
| The Pig-latin word | string | varying | returned | piglatinWord |
| Portion of the English word from its first vowel until its end |
string | varying | local | lastPart |
| Consonants at the beginning of the English word | string | varying | local | firstPart |
| "ay" | string | constant | local | -- |
This gives us the following specification for our function:
Receive: englishWord, a string. Return: piglatinWord, a string.Use this specification to create a stub for a function named Piglatin() in translate.cpp; then add a prototype for Piglatin() above the main function.
Function Operations. Our behavioral description lists these operations:
| Description | Defined? | Name | Library? | |
|---|---|---|---|---|
| 1 | Receive englishWord (a string) from caller | yes | function call mechanism |
built-in |
| 2 | Find the position of the first vowel in a string | yes | find_first_of() | string |
| 3 | Check that the word actually contains a vowel | yes | assert() | cassert |
| 4 | Access the substring of a word from its first vowel to its end |
yes | substr() | string |
| 5 | Access the substring of a word from its beginning until just before its first vowel |
yes | substr() | string |
| 6 | Combine two substrings into a single string | yes | + | string |
| 7 | Return a string to the caller | yes | return | built-in |
Function Algorithm. Organizing these operations gives us this algorithm:
0. Receive englishWord from the caller.
1. Find vowelPosition, the position of the first vowel in englishWord;
check that a vowel was found.
2. Build lastPart, the substring of englishWord starting at
vowelPosition and running to its end.
3. Build firstPart, the substring of englishWord starting at
its beginning and ending just before vowelPosition.
4. Build piglatinWord by concatenating lastPart, firstPart, and "ay".
5. Return piglatinWord.
1. Find vowelPosition, the position of the first vowel in englishWord; check that a vowel was actually found. Since we want to find the first vowel in englishWord, we search the preceding list for a string operation to perform this operation. In the list, we see the find_first_of() function member which can be used for this purpose. The required pattern is a string listing each vowel, and we should begin searching at the first character, whose index is zero. The first line in our function is thus
int vowelPosition = englishWord.find_first_of("aeiouyAEIOUY", 0);
That is, if englishWord is as follows:
then this statement will search englishWord for the first occurrence of a, e, i, o, u, y, A, E, I, O, U, or Y; beginning with the character at index 0, and will thus return 1, the index of a. Add this statement to the stub of Piglatin().
Our list of string function members also tells us that find_first_of() returns the special constant string::npos if none of the characters in pattern occur in the target. We can use this in an assert() to check that a vowel was found, so add a call to assert() to check that vowelPosition is not equal to string::npos.
Use the compiler to check the syntax of your program thus far (aside from not returning anything), and then continue to the next part of the exercise.
2. Build lastPart, the substring of englishWord starting at its first vowel and running to its end. If we again search through the list of string operations, we see that the substr() operation provides a way to accomplish this step. In our case, we want to grab the substring of englishWord beginning at vowelPosition, and whose length is the number of characters between vowelPosition and the end of englishWord. (Calculating this length is the tricky part.) Since the string function member size() gives us the total number of characters in the string, and the index of the first character is always zero, we can get the length of the substring by subtracting vowelPosition from the size() of the string:
So the second step of our algorithm can be encoded like this:
string lastPart = englishWord.substr(vowelPosition,
englishWord.size() - vowelPosition);
As before, use the compiler to check the syntax of this statement,
and continue when it is correct.
3. Build firstPart, the substring of initial consonants of englishWord. To perform step 3, we can again use the substr() function member of class string. Since we want to grab the consonants at the beginning of the string, we should start grabbing at index 0. As before, computing the number of characters to grab is the hard part: Since vowelPosition contains the index of the first vowel, and index values start at zero, the value of vowelPosition is also the number of consonants at the beginning of the string:
Using this information, add a statement to Piglatin() that encodes step 3, using the substr() function member. Test its syntax using the compiler, and continue when it is correct.
4. Build piglatinWord by concatenating lastPart, firstPart, and "ay". The operation of combining two or more string values into a single string is called concatenation. For example, the concatenation of the string values "en" and "list" produces the string "enlist", while the concatenation of "list" and "en" produces "listen". Order is thus significant in performing concatenation.
Examining the list of string operations, we see that string concatenation can be performed using the plus (+) operator. This step is thus easily coded as follows:
string pigLatinWord = lastPart + firstPart + "ay";Add this statement to Piglatin(), and use the compiler to check the correctness of its syntax; then continue to the last step.
5. Return pigLatinWord. This is a simple return statement, with which you should be familiar. Add the necessary return statement, and then compile and run your program, testing it with words that do not begin with a vowel. If your program compiles correctly but does not correctly translate words beginning with consonants into pig-late, track down your logic error before continuing.
To track down a logic error, run the debugger (F11) and use it to step into your Piglatin() function. Use the step-over command (F10) to step over the calls to find_first_of() and substr(). In the auto window at the bottom of the window, note that the values of lastPart and firstPart are listed as
{...}
This is because as class objects, lastPart and firstPart
are made up of multiple values, including their length, capacity,
and the sequence of characters they store.
To view these values, click on the boxed plus sign next to their names.
The values of the string stored in each object is next to its
What happens if you enter a word that begins with a vowel? Why?
In this part of the exercise, you are to extend function Piglatin() with the necessary code to handle words that begin with a vowel. Whereas Part I "led you by the hand", you are to figure out what must be done in Part II (feel free to consult with your lab partner).
Begin by describing how the function's behavior must differ from its current behavior. List any additional objects and/or operations that are required to achieve this new behavior. Modify the algorithm from Part I accordingly and then use it to update the code in Piglatin().
Pictures are often helpful, especially when figuring out proper index values, so try drawing a picture of a sample string if you get stuck.
String, Substring, Concatenation, String Input, String Output, String Length, String Replacement, String Searching, String Pattern Matching (Forward and Reverse).
Forward to the Homework Projects