# Programming a Decoder

Now that we have a program to turn a message into a sequence of numbers, it would be nice if our friend on the other end had a similar program to turn the numbers back into a readable message. Let's solve that problem next. Our decoder program will prompt the user for a sequence of numbers representing ASCII codes and then print out the text message corresponding to those codes. This program presents us with a couple of challenges; we'll address these as we go along.

The overall outline of the decoder program looks very similar to the encoder program. One change in structure is that the decoding version will collect the characters of the message in a string and print out the entire message at the end of the program. To do this, we need to use an accumulator variable, a pattern we saw in the factorial program from the previous chapter. Here is the decoding algorithm:

get the sequence of numbers to decode message = ""

for each number in the input:

convert the number to the appropriate character add the character to the end of message print the message

Before the loop, the accumulator variable message is initialized to be an empty string, that is a string that contains no characters (""). Each time through the loop a number from the input is converted into an appropriate character and appended to the end of the message constructed so far.

The algorithm seems simple enough, but even the first step presents us with a problem. How exactly do we get the sequence of numbers to decode? We don't even know how many numbers there will be. To solve this problem, we are going to rely on some more string manipulation operations.

First, we will read the entire sequence of numbers as a single string using raw_input. Then we will split the big string into a sequence of smaller strings, each of which represents one of the numbers. Finally, we can iterate through the list of smaller strings, convert each into a number, and use that number to produce the corresponding ASCII character. Here is the complete algorithm:

get the sequence of numbers as a string, inString split inString into a sequence of smaller strings message = ""

for each of the smaller strings:

change the string of digits into the number it represents append the ASCII character for that number to message print message

This looks complicated, but Python provides some functions that do just what we need.

We saw in Chapter 3 that Python provides a standard math library containing useful functions for computing with numbers. Similarly, the string library contains many functions that are useful in string-manipulation programs.

For our decoder, we will make use of the split function. This function is used to split a string into a sequence of substrings. By default, it will split the string wherever a space occurs. Here's an example:

>>> string.split("Hello string library!") ['Hello', 'string', 'library!']

You can see how split has turned the original string "Hello string library!" into a list of three strings: "Hello", "string" and "library!".

By the way, the split function can be used to split a string at places other than spaces by supplying the character to split on as a second parameter. For example, if we have a string of numbers separated by commas, we could split on the commas.

>>> string.split("32,24,25,57", ",") ['32', '24', '25', '57']

Since our decoder program should accept the same format that was produced by the encoder program, namely a sequence of numbers with spaces between, the default version of split works nicely.

>>> string.split("87 104 97 116 32 97 32 83 111 117 114 112 117 115 115 33") ['87', '104', '97', '116', '32', '97', '32', '83', '111', '117', '114', '112', '117', '115', '115', '33']

Notice that the resulting list is not a sequence of numbers, it is a sequence of strings. It just so happens these strings contain only digits and could be interpreted as numbers.

All that we need now is a way of converting a string containing digits into a Python number. One way to accomplish this is with the Python eval function. This function takes any string and evaluates it as if it were a Python expression. Here are some interactive examples of eval:

>>> numStr = "500" >>> eval(numStr) 500

16.45

>>> x = eval(raw_input("Enter a number ")) Enter a number 3.14 >>> print x 3.14

The last pair of statements shows that the eval of a raw_input produces exactly what we would expect from an input expression. Remember, input evaluates what the user types, and eval evaluates whatever string it is given.

Using split and eval we can write our decoder program.

# numbers2text.py

# A program to convert a sequence of ASCII numbers into

import string # include string library for the split function, def main():

print "This program converts a sequence of ASCII numbers into"

print "the string of text that it represents."

print

# Get the message to encode inString = raw_input("Please enter the ASCII-encoded message: ")

# Loop through each substring and build ASCII message message = ""

for numStr in string.split(inString):

asciiNum = eval(numStr) # convert digit string to a number message = message + chr(asciiNum) # append character to message print "The decoded message is:", message main()

Study this program a bit, and you should be able to understand exactly how it accomplishes its task. The heart of the program is the loop.

for numStr in string.split(inString): asciiNum = eval(numStr) message = message + chr(asciiNum)

The split function produces a sequence of strings, and numStr takes on each successive (sub)string in the sequence. I called the loop variable numStr to emphasize that its value is a string of digits that represents some number. Each time through the loop, the next substring is converted to a number by evaling it. This number is converted to the corresponding ASCII character via chr and appended to the end of the accumulator, message. When the loop is finished, every number in inString has been processed and message contains the decoded text.

Here is an example of the program in action:

>>> import numbers2text

This program converts a sequence of ASCII numbers into the string of text that it represents.