.. _string-examples: String Examples ############### .. include:: /header.inc .. vim:filetype=rst spell: We need to work through a problem involving strings that is a bit more involved than the simple example we worked on last time. How about writing a "palindrome" checker. What is a palindrome? ********************* A palindrome is a word or phrase that is the same forwards and backwards. A simple example of one is "anna". A classic example is "Able was I ere I saw Elba". Now, we cannot simply reverse the sequence of characters and see the palindrome. What we need to do is check that the letters of the test string are identical forwards and backwards. So, how do we do this? Support functions ***************** To check if a given string is a palindrome, we need to change all the letters in the string to lower case, then get rid of things like punctuation or spaces. After doing all of that, we need to reverse the string and compare it to the original to see if they are equal! Here is some code that could confirm if a sample string is a palindrome: .. literalinclude:: code/Palindrome.cpp :lines: 34-39 Here, we have introduced a few supporting functions that take an input string and return a modified output string: * ``strip_extra`` - removes non letter characters * ``lower_case`` - returns the input string converted to lower case * ``reverse`` - returns the input string reversed. This is simple. Here is a program that we might use to test our ideas: .. literalinclude:: code/Palindrome.cpp :lines: 19-32 In this chunk of code, we assume we have setup an array of test strings, and we want to output the string and a statement indicating if that string is, or is not, a palindrome. Example strings *************** I did what everyone is expected to do today, Googled for a few Palindromes! This is what I got: .. literalinclude:: code/Palindrome.cpp :lines: 6-12 The supporting routines *********************** All we need to do to complete this project is to build our supporting routines. lower_case() ============ Let's start off with an easy one, converting to lower case. To build this routine, we need to check each character, easy enough to do in a simple loop. However, we might need to change any letter, and we run into a potential issue. Can we alter the string "in place"? C++ is an evolving standard. In older versions of the language, it might not be possible to do a simple change. As an example, what happens if you try something like this: .. code-block:: c++ string test = "demo string"; test[0] = 'D'; test[5] = 'S'; test[10] = '!'; Should this be possible? In our old way of thinking, a string is just an array of characters. Adding another character at the end of the current string would surely botch things, since we know (or should know) that the string probably has some indicator that we have asked to modify something beyond the current length of the string. But a string in C++ is a proper class, and the authors of that class thought through all the ways folks might like to (sb)use their creation. So how do we figure out what we can really do with a string. Well Luke, use the Force! Actually, use the documentation! So, to build this routine safely, I needed to search the documentation for the ``string`` class and see what functions (or methods as they are properly called) are available. I found a simple method named ``append`` that lets you add something to an existing string, and that seemed to be what I needed. .. note:: Actually, this ``append`` method is a good example of "polymorphism", somehting we will look at next class. For now, it just means we can "append" lots of different things to a string, including a single character, which is what I will use in this example code! I decided that the easy way to build the final string I want would be to create an empty string, then add (append) a single character at a time, converting that character to lower case as required. There is a nice C++ function I can use to do this: ``tolower()``, which takes a single character and returns the lower case version of that character. It is smart enough not to try to lower case numbers or punctuation, so this code will do what we need! .. note:: BTW! Python does not let you modify a string in place, you mist change the string by creating a new string from the old one, so this logic is exacty what you would do in Python. Here is the code we need: .. literalinclude:: code/Palindrome.cpp :lines: 41-47 The first parameter to the ``append`` function is the size (in bytes) of the thing you are adding. One byte in this code. strip_extra() ============= Using this same pattern, we can strip the string of unwanted characters. All we need to do here is check each character to make sure it is a letter. I am going to assume that we only call this function after we lower case all the letters in the string This is the code I ended up with: .. literalinclude:: code/Palindrome.cpp :lines: 49-59 reverse() ========= The last function we need takes an input string and returns that string in reverse. Once again, we use the same pattern to build up the output string. We use a ``for-loop`` that indexes the string in reverse to get this done. Here is the code: .. literalinclude:: code/Palindrome.cpp :lines: 61-70 Wrappin up ********** Here is the complete program: .. literalinclude:: code/Palindrome.cpp Here is the output produced by this code: .. code-block:: text "A Toyota's a Toyota" is a palindrome "Able was I ere I saw Elba" is a palindrome "A Santa at NASA" is a palindrome "Are we not drawn onward to new era" is a palindrome "This is not a palindrome" is not a palindrome