Encode Strings Using a Character Map
This function encodes strings using a simple character map. Letters are mapped to the letter that is 13 positions away in the alphabet, so A becomes N (and N becomes A), B becomes O, and so on. In addition, numbers are mapped to the symbol that occupies the same key on a standard U.S. keyboard, so 1 becomes !, 2 becomes @ (and vice versa), and so on. Other characters are left alone.
The built-in function index(), when called on a string, returns the index in the string of the first occurrence of a substring: It raises a ValueError exception if the substring is not found:
location = index("hey there", "th")
The function ord() converts a one-character string to its ASCII value, and chr() does the reverse, converting a number to a one-character string whose ASCII value is that number:
numA = ord("A") # numA will be 65
strA = chr(65) # strA will be "A"
Source Code
1. numbers = "1234567890"
2. symbols = "!@#$%^&*()"
3.
4. def encode ( string ):
5. """ Encodes string using a simple mapping
6. string: the input string
7.
8. Returns the mapped string.
9. """
10.
11. # fill in the maps; a character at a given position
12. # in map1 maps to the character at the same position
13. # in map2, and vice versa.
14.
15. map1, map2 = [ ], [ ]
16.
17. # first do the letters, put the first half of the
18. # alphabet in map1, then the rest in map2...
19.
20. for k in range(ord("A"), ord("A")+13):
21. map1.append(chr(k))
22. for k in range(ord("a"), ord("a")+13):
23. map1.append(chr(k))
24. map2 = [chr(ord(x)-13) for x in map1]
25.
26. # ...now do the numbers/symbols
27.
28. for k in range(len(numbers)):
29. map1.append(numbers[k])
30. map2.append(symbols[k])
31.
32. newstring = ""
33.
34. # now map any character in map1 to the character at
35. # the same position in map2, and any character in map2
36. # to the same characters in map1.
37.
38. for c in string:
39. if (c in map1):
40. newc = map2[map1.index(c)]
41. elif (c in map2):
42. newc = map1[map2.index(c)]
43. else:
44. newc = c
45.
46. newstring = newstring + newc
47.
48. return newstring
Suggestions
As previously mentioned, the index() function raises a ValueError exception if the substring is not found. Because the program does not catch the exception, it would be an error if it were thrown. Check that this won't happen. Describe precisely the intended relationship between map1 and map2. Does the initialization of the two variables maintain this relationship? Think of empty, trivial, and already solved inputs for this function. Track where the return value newstring is modified and ensure that it is done correctly.
Hints
Walk through the function with the following inputs:
A single lowercase letter: string == "a" A single uppercase letter: string == "A" A mix of letters and numbers: string == "abc123" Letters and a symbol: string == "bye?"
Explanation of the Bug
The code on line 24 to initialize the letter parts of map2
map2 = [chr(ord(x)-13) for x in map1]
has a B.expression error. The code intends to initialize map1 with the letters in the first half of the alphabet and map2 with the letters in the second half. This means that the ASCII values in map2 should be 13 higher than those in map1, so the code should be as follows:
map2 = [chr(ord(x)+13) for x in map1]
As a result of this error, the program maps the letters A through M, in upper- and lowercase, to a random collection of numbers, punctuation, and even other (incorrect) letters based on the happenstance arrangement of the ASCII table. All that mapping then also happens in reverse because of the way the program is designed.
|