views:

540

answers:

8

Hello! I want to change every letter in a text to after next following letter. But this program doesnt work. Does anyone know why. Thanks in advance. There is also a minor problem with y and z.

import string

letters = string.ascii_lowercase
text=("g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj. ")
for x in range(1,24):
    text.replace(letters[x],letters[x+2])
print(text)
+3  A: 

Your first error is that strings are immutable so your replace isn't doing anything. To replace characters in a string you have to reassign:

text = text.replace(a, b)

But this is a very inefficient way to do it anyway as you are creating many temporary strings which will just be discarded again shortly afterwards. You should try to iterate over the string handling one character at a time and the join the result.

I won't give away the full solution so that you can have another go.

Mark Byers
+2  A: 
Hamish Grubijan
You can change `'a' <= t and t <= 'z'` to `'a' <= t <= 'z'` as a shortcut. Also the second pair of `()` for the generator aren't necessary since the generator is the only argument.
Chris Lutz
A: 

aren't you forgetting forgetting base cases?

problems that I see are: 1)

for x in range(1,24):

-- shouldn't that be your string length?

2)

text.replace(letters[x],letters[x+2])

what happens when x == 23? I suggest using ((x+2) % len(letters)) or something like that.

also, are you sure that text is being updated? I know python treats strings as arrays, but does that mean that the letters are updated everytime you do replace?

try:

text = text.replace(letters[x],letters[x+2])
piggles
1) No, he's trying to replace each letter one at a time, and replacing letters 25 and 26 will cause an error with the current method. 2) When x == 23, there's no problem because there are 26 English letters.
Michael Myers
Oh sorry, I misread the code. I thought (1,24) was a standin for len(text).At any rate, it should be (1,26) (or (0,25) ?) and replace(letters[x],letters[(x+2)%26]
piggles
+5  A: 

Strings are immutable in python.

So text.replace returns a string, but doesn't change its original string.

Given that, you shouldn't actually use text.replace, since you would have to change the string 24 (or probably 26; see below) times. Rather, you can actually create a translation table to do all the changes at once, and use string.translate.

To do that, you should first use string.maketrans to convert from the letters to the second letter following (and what do you want to do with 'y' and 'z'? I expect they should probably become 'a' and 'b'). That will give you a translation table over all possible characters for translate.

Andrew Jaffe
This is the correct way to do it.
Tor Valamo
The string translate/maketrans functions are pretty old fashioned, not unicode aware, and relatively awkward to use IMHO. For English strings like the one given, yes it works, but I don't think it is better than writing a simple function that maps a character to a new character and using that function in a comprehension. The only advantage of the string.translate is that it will be faster, and to be honest I don't think that's enough to make up for all the warts.
Mark Byers
+2  A: 

This should do what you want:

>>> rot = lambda xs: (xs + [xs[0]])[1:]
>>> apply = lambda n,f,x: (n == 0) and x or f(apply(n-1,f,x))
>>> abc = map(chr,range(ord('a'),ord('z')+1))
>>> d = dict(zip(list(abc),apply(2,rot,(list(abc)))))
>>> s = "g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj. "
>>> reduce(lambda a,b:a+b,map(lambda c: d.get(c,' '),list(s)),"")
'i hope you didnt translate it by hand  thats what computers are for  doing it in by hand is inefficient and that s why this text is so long  using string maketrans   is recommended  now apply on the url  '
jetxee
Python is so beautiful!
jetxee
+2  A: 

Solution closest to yours is:

letters = string.ascii_lowercase
uletters = string.ascii_uppercase
text=("g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj. ")
for x in range(0,26):
    text=text.replace(letters[x-2],uletters[x])
print(text.lower())
Antony Hatchkins
A: 

ill post my solution someone tell me why it doesnt work

Steve
A: 

why doesnt this work? it gives me a bunch of z and a

 import string

letters = string.ascii_lowercase

text=("g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj.")
for x in range(0,26):
    try:
        print letters[x]
        text = text.replace(letters[x],letters[x+2])
    except:
        text = text.replace(letters[x],"a")
        break
print text
Steve