• No results found

As I’ve noted from time to time in the text, several of the functions in this chapter seem ideal for inclusion in a library. Once you have written these functions as part of one application, it would be silly not to use them in other applications that need to perform the same operations. While functions like wordToPigLatin are unlikely to show up anywhere else, you will often have occasion to use functions like toUpperCase and startsWith. To avoid having to rewrite them or to cut-and-paste the code, it makes sense to put those functions into a library so that you always have them available.

The Stanford libraries distributed with the book include an interface called strlib.h that exports the functions shown in Table 3-6. You can see on this list several functions whose definitions appear in this chapter. In the exercises, you will have a chance to fill in the definitions of some of the others, including endsWith and trim. The first four functions in Table 3-6, all of which are concerned with converting numeric values to string form, require techniques that are beyond the limits of your knowledge of C++, but only for the moment. In Chapter 4, you will learn how to use a new data type called a stream, which will make it easy to implement these functions.

T A B L E 3 - 6 Functions exported by the strlib.h interface

integerToString(n) Converts an integer into the corresponding string of digits.

stringToInteger(str) Converts a string of digits into an integer.

realToString(d) Converts a floating-point number into the corresponding string form.

stringToReal(str) Converts a string representing a real number into its corresponding value.

toUpperCase(str) Returns a new string in which all lowercase characters have been converted into their uppercase equivalents.

toLowerCase(str) Returns a new string in which all uppercase characters have been converted into their lowercase equivalents.

equalsIgnoreCase(s1, s2) Returns true if s1 and s2 are equal discounting differences in case. startsWith(str, prefix) Returns true if the string str starts with the specified prefix, which

may be either a string or a character.

endsWith(str, suffix) Returns true if the string str ends with the specified suffix, which may be either a string or a character.

trim(str) Returns a new string after removing any whitespace characters from the beginning and end of the argument.

Summary

In this chapter, you have learned how to use the <string> library, which makes it possible to write string-processing functions without worrying about the details of the underlying representation. The important points in this chapter include:

• The <string> library exports a class called string that represents a sequence of characters. Although C++ also includes a more primitive string type to maintain compatibility with the C programming language, it is best to use the string class in any programs that you write.

• If you use the >> extraction operator to read string data, the input stops at the first whitespace character. If you want to read an entire line of text from the user, it is usually better to use the getLine function exported by the simpio.h interface.

• The most common methods exported by the string class appear in Table 3-1 on page 128. Because string is a class, the methods use the receiver syntax

instead of the traditional functional form. Thus, to obtain the length of a string stored in the variable str, you need to invoke str.length().

• Several of the methods exported by the string class destructively modify the receiver string. Giving clients free access to methods that change the internal state of an object makes it harder to protect that object’s integrity. The programs in this book therefore minimize the use of these methods.

• The string class uses operator overloading to simplify many common string operations. For strings, the most important operators are + (for concatenation), [] (for selection), and the relational operators.

• The standard pattern for iterating through the characters in a string is for (int i = 0; i < str.length(); i++) { . . . body of loop that manipulates str[i] . . .

}

• The standard pattern for growing a string by concatenation is string str = "";

for (whatever loop header line fits the application) { str += the next substring or character;

}

• The <cctype> library exports several functions for working with individual characters. The most important of these functions appear in Table 3-2.

Review questions

1. What is the difference between a character and a string?

2. True or false: If you execute the lines string line;

cin >> line;

the program will read an entire line of data from the user and store it in the variable line.

3. Which arguments to the getline function are passed by reference? 4. What is the difference between a method and a free function?

5. True or false: In C++, you can determine the length of the string stored in the variable str by calling length(str).

6. If you call s1.replace(0, 1, s2), which string is the receiver?

7. What is the effect of the + operator when it is used with two string operands? 8. When C++ evaluates the expression s1<s2, what rule does the string class

use to compare the string values?

9. What two syntactic forms does this chapter describe for selecting an individual character from a string? How do these two syntactic forms differ in their implementation?

10. When you select an individual character from a C++ string, you can use either the at method or the standard subscript notation using square brackets. From the client’s perspective, what is the difference between these two options? 11. True or false: If you assign the value of the string variable s1 to the string

variable s2, the string class copies the characters so that subsequent changes to the characters in one string will not affect the characters in the other. 12. True or false: The index positions in a string begin at 0 and extend up to the

length of the string minus 1.

13. What are the arguments to the substr method? What happens if you omit the second argument?

14. What value does the find method return to indicate that the search string does not appear?

15. What are the arguments to the substr method? What happens if you omit the second argument?

16. What is the significance of the optional second argument to the find method? 17. What is the effect of each of the following calls to the <string> library:

string s = "ABCDE" string t = ""; a. s.length() f. s.replace(0, 2, "Z") b. t.length() g. s.substr(0, 3) c. s[2] h. s.substr(4) d. s + t i. s.substr(3, 9) e. t += 'a' j. s.substr(3, 3)

18. What is the pattern for iterating through each character in a string?

19. How does this pattern change if you want to iterate through the characters in reverse order, starting with the last character and ending with the first? 20. What is the pattern for growing a string through concatenation?

21. What is the result of each of the following calls to the <cctype> library:

a. isdigit(7) d. toupper(7)

b. isdigit('7') e. toupper('A')

c. isalnum(7) f. tolower('A')

22. Why does C++ support both a string class and a more primitive string type? 23. How can you convert a primitive string value to a C++ string? How can you

specify a conversion in the opposite direction?

Exercises

1. Implement the function endsWith(str,suffix), which returns true if str ends with suffix. Like its startsWith counterpart, the endsWith function should allow the second argument to be either a string or a character.

2. The strlib.h function exports a function trim(str) that returns a new string formed by removing all whitespace characters from the beginning and end of str. Write the corresponding implementation.

3. Without using the built-in string method substr, implement a free function substr(str,pos,n) that returns the substring of str beginning at position pos and containing at most n characters. Make sure that your function correctly applies the following rules:

• If n is missing or greater than the length of the string, the substring should extend through the end of the original string.

• If pos is greater than the length of the string, substr should call error with an appropriate message.

4. Implement a function capitalize(str) that returns a string in which the initial character is capitalized (if it is a letter) and all other letters are converted to lowercase. Characters other than letters are not affected. For example, both capitalize("BOOLEAN") and capitalize("boolean") should return the string "Boolean".

5. In most word games, each letter in a word is scored according to its point value, which is inversely proportional to its frequency in English words. In Scrabble™, the points are allocated as follows:

Points Letters 1 A, E, I, L, N, O, R, S, T, U 2 D, G 3 B, C, M, P 4 F, H, V, W, Y 5 K 8 J, X 10 Q, Z

For example, the word "FARM" is worth 9 points in Scrabble: 4 for the F, 1 each for the A and the R, and 3 for the M. Write a program that reads in words and prints out their score in Scrabble, not counting any of the other bonuses that occur in the game. You should ignore any characters other than uppercase letters in computing the score. In particular, lowercase letters are assumed to represent blank tiles, which can stand for any letter but have a score of 0. 6. An acronymis a new word formed by combining, in order, the initial letters of

a series of words. For example, the word scuba is an acronym formed from the first letters in self-contained underwater breathing apparatus. Similarly,

function acronym that takes a string and returns the acronym formed from that string. To ensure that your function treats hyphenated compounds like

self-contained as two words, it should define the beginning of a word as any alphabetic character that appears either at the beginning of the string or after a nonalphabetic character.

7. Write a function

string removeCharacters(string str, string remove); that returns a new string consisting of the characters in str after removing all instances of the characters in remove. For example, if you call

removeCharacters("counterrevolutionaries", "aeiou") the function should return "cntrrvltnrs", which is the original string after removing all of its vowels.

8. Modify your solution to exercise 7 so that, instead of using a function that returns a new string, you define a function removeCharactersInPlace that removes the letters from the string passed as the first argument.

9. The waste of time in spelling imaginary sounds and their history (or etymology as it is called) is monstrous in English . . .

—George Bernard Shaw, 1941 In the early part of the 20th century, there was considerable interest in both England and the United States in simplifying the rules used for spelling English words, which has always been a difficult proposition. One suggestion advanced as part of this movement was to eliminate all doubled letters, so that

bookkeeper would be written as bokeper and committee would become comite. Write a function removeDoubledLetters(str) that returns a new string in which any duplicated characters in str have been replaced by a single copy. 10. Write a function

string replaceAll(string str, char c1, char c2); that returns a copy of str with every occurrence of c1 replaced by c2. For example, calling

replaceAll("nannies", 'n', 'd'); should return "daddies".

Once you have coded and tested this function, write an overloaded version string replaceAll(string str, string s1, string s2); that replaces all instances of the string s1 with the replacement string s2. 11. The concept of a palindrome is often extended to full sentences by ignoring

punctuation and differences in the case of letters. For example, the sentence

Madam, I’m Adam.

is a sentence palindrome, because if you only look at the letters and ignore any distinction between uppercase and lowercase letters, it reads identically backward and forward.

Write a predicate function isSentencePalindrome(str) that returns true if the string str fits this definition of a sentence palindrome. For example, you should be able to use your function to write a main program capable of producing the following sample run:

12. Write a function createRegularPlural(word) that returns the plural of word formed by following these standard English rules:

a. If the word ends in s, x, z, ch, or sh, add es to the word.

b. If the word ends in a y preceded by a consonant, change the y to ies.

c. In all other cases, add just an s.

Write a test program and design a set of test cases to verify that your program works.

13. Like most other languages, English include two types of numbers. The cardinal numbers (such as one, two, three, and four) are used in counting; the ordinal numbers (such as first, second, third, and fourth) are used to indicate a position in a sequence. In text, ordinals are usually indicated by writing the

SentencePalindrome

This program tests for sentence palindromes. Indicate the end of the input with a blank line. Enter a sentence: Madam, I'm Adam.

That sentence is a palindrome.

Enter a sentence: A man, a plan, a canal -- Panama! That sentence is a palindrome.

Enter a sentence: Not a palindrome. That sentence is not a palindrome. Enter a sentence:

digits in the number, followed by the last two letters of the English word that names the corresponding ordinal. Thus, the ordinal numbers first, second, third, and fourth often appear in print as 1st, 2nd, 3rd, and 4th. The ordinals for 11, 12, and 13, however, are 11th, 12th, and 13th. Devise a rule that determines what suffix should be added to each number, and then use this rule to write a function createOrdinalForm(n) that returns the ordinal form of the number n as a string.

14. When large numbers are written out on paper, it is traditional—at least in the United States—to use commas to separate the digits into groups of three. For example, the number one million is usually written in the following form:

1,000,000

To make it easier for programmers to display numbers in this fashion, implement a function

string addCommas(string digits);

that takes a string of decimal digits representing a number and returns the string formed by inserting commas at every third position, starting on the right. For example, if you were to execute the main program

int main() { while (true) {

string digits = getLine("Enter a number: "); if (digits == "") break;

cout << addCommas(digits) << endl; }

return 0; }

your implementation of the addCommas function should be able to produce the following sample run:

AddCommas Enter a number: 17 17 Enter a number: 1001 1,001 Enter a number: 12345678 12,345,678 Enter a number: 999999999 999,999,999 Enter a number:

15. As written, the PigLatin program in Figure 3-2 behaves oddly if you enter a string that includes words beginning with an uppercase letter. For example, if you were to capitalize the first word in the sentence and the name of the Pig Latin language, you would see the following output:

Rewrite the wordToPigLatin function so that any word that begins with a capital letter in the English line still begins with a capital letter in Pig Latin. Thus, after making your changes in the program, the output should look like this:

16. Most people—at least those in English-speaking countries—have played the Pig Latin game at some point in their lives. There are, however, other invented “languages” in which words are created using some simple transformation of English. One such language is called Obenglobish, in which words are created by adding the letters ob before the vowels (a, e, i, o, and u) in an English word. For example, under this rule, the word english gets the letters ob added before the e and the i to form obenglobish, which is how the language gets its name.

In official Obenglobish, the o b characters are added only before vowels that are pronounced, which means that a word like game would become

gobame rather than gobamobe because the final e is silent. While it is impossible to implement this rule perfectly, you can do a pretty good job by adopting the rule that the ob should be added before every vowel in the English word except

• Vowels that follow other vowels • An e that occurs at the end of the word

PigLatin

This program translates English to Pig Latin. Enter English text: This is Pig Latin.

Pig Latin output: isThay isway igPay atinLay.

PigLatin

This program translates English to Pig Latin. Enter English text: This is Pig Latin. Pig Latin output: Isthay isway Igpay Atinlay.

Write a function obenglobish that takes an English word and returns its Obenglobish equivalent, using the translation rule given above. For example, if you used your function with the main program

int main() { while (true) {

string word = getLine("Enter a word: "); if (word == "") break;

string trans = obenglobish(word);

cout << word << " -> " << trans << endl; }

return 0; }

you should be able to generate the following sample run:

17. If you played around with codes and ciphers as a child, the odds are good that you at some point used a cyclic cipher—which is often called a Caesar cipher because the Roman historian Suetonius records that Julius Caesar used this technique—in which you replace each letter in the original message by the letter that appears a fixed distance ahead in the alphabet. As an example, suppose that you wanted to encode a message by shifting every letter ahead three places. In this cipher, each A becomes an D, B becomes E, and so on. If you reach the end of the alphabet, the process cycles around to the beginning, so that X becomes A,Y becomes B, and Z becomes C.

To implement a Caesar cipher, you should first define a function string encodeCaesarCipher(string str, int shift); that returns a new string formed by shifting every letter in str forward the number of letters indicated by shift, cycling back to the beginning of the

Obenglobish Enter a word: english

english -> obenglobish Enter a word: hobnob

hobnob -> hobobnobob Enter a word: gooiest

gooiest -> gobooiest Enter a word: amaze

amaze -> obamobaze Enter a word: rot

rot -> robot Enter a word:

alphabet if necessary. After you have implemented encodeCaesarCipher, write a program that generates the following sample run:

Note that the transformation applies only to letters; any other characters are copied unchanged to the output. Moreover, the case of letters is unaffected: lowercase letters come out as lowercase, and uppercase letters come out as uppercase. You should also write your program so that a negative value of shift means that letters are shifted toward the beginning of the alphabet instead of toward the end, as illustrated by the following sample run: