Joe
Joe

Reputation: 923

Shift cipher in Python: error using ord

I want to replace each character of a string by a different one, shifted over in the alphabet. I'm shifting by 2 in the example below, so a -> c, b -> d, etc.

I'm trying to use a regular expression and the sub function to accomplish this, but I'm getting an error.

This is the code that I have:

p = re.compile(r'(\w)')
test = p.sub(chr(ord('\\1') + 2), text)
print test

where the variable text is an input string.

And I'm getting this error:

TypeError: ord() expected a character, but string of length 2 found

I think the problem is that I the ord function is being called on the literal string "\1" and not on the \w character matched by the regular expression. What is the right way to do this?

Upvotes: 3

Views: 3120

Answers (4)

jags
jags

Reputation: 557

def CaesarCipher(s1,num):
new_str = ''
for i in s1:
    asc_V = ord(i)

    if asc_V in range(65, 91):
        if asc_V + num > 90:
            asc_val = 65 + (num - 1 - (90 - asc_V))
        else:
            asc_val = asc_V + num

        new_str = new_str + chr(asc_val)


    elif (asc_V in range(97, 123)):
        if asc_V + num > 122:
            asc_val = 97 + (num - 1 - (122 - asc_V))
        else:
            asc_val = asc_V + num

        new_str = new_str + chr(asc_val)

    else:
        new_str = new_str + i

return new_str        

print (CaesarCipher("HEllo", 4))

print (CaesarCipher("xyzderBYTE", 2))

Upvotes: 0

ninjagecko
ninjagecko

Reputation: 91149

Full version

def shouldShift(char):
    return char in string.lowercase

def caesarShift(string, n):
    def letterToNum(char):
        return ord(char)-ord('a')
    def numToLetter(num):
        return chr(num+ord('a'))

    def shiftByN(char):
        return numToLetter((letterToNum(char)+n) % 26)

    return ''.join((shiftByN(c) if shouldShift(c) else c) for c in string.lower())

One-liner

If you really want a one-liner, it would be this, but I felt it was uglier:

''.join(chr((ord(c)-ord('a')+n)%26 + ord('a')) for c in string)

Demo

>>> caesarShift(string.lowercase, 3)
'defghijklmnopqrstuvwxyzabc'

Upvotes: 2

Óscar López
Óscar López

Reputation: 236112

Try this, using list comprehensions:

input = 'ABC'
''.join(chr(ord(c)+2) for c in input)
> 'CDE'

It's simpler than using regular expressions.

Upvotes: 1

Rob Wouters
Rob Wouters

Reputation: 16327

It won't work like this. Python first runs chr(ord('\\') + 2 and then passes that result to p.sub.

You need to put it in a separate function or use an anonymous function (lambda):

p = re.compile(r'(\w)')
test = p.sub(lambda m: chr(ord(m.group(1)) + 2), text)
print test

Or better yet use maketrans instead of regular expressions:

import string

shift = 2

t = string.maketrans(string.ascii_lowercase, string.ascii_lowercase[shift:] +
                                             string.ascii_lowercase[:shift])
string.translate(text, t)

Upvotes: 4

Related Questions