Short rot13 function - Python [closed]

笑着哭i 提交于 2020-01-18 03:57:26

问题


I am searching for a short and cool rot13 function in Python ;-) I've written this function:

def rot13(s):
    chars = "abcdefghijklmnopqrstuvwxyz"
    trans = chars[13:]+chars[:13]
    rot_char = lambda c: trans[chars.find(c)] if chars.find(c)>-1 else c
    return ''.join( rot_char(c) for c in s ) 

Can anyone make it better? E.g supporting uppercase characters.


回答1:


Here's a maketrans/translate solution

import string
rot13 = string.maketrans( 
    "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 
    "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
string.translate("Hello World!", rot13)
# 'Uryyb Jbeyq!'



回答2:


It's very simple:

>>> import codecs
>>> codecs.encode('foobar', 'rot_13')
'sbbone'



回答3:


This works on Python 2 (but not Python 3):

>>> 'foobar'.encode('rot13')
'sbbone'



回答4:


The maketrans and translate functions in the string module are handy for this type of thing. Of course, the encode method in Amber's response is even handier for this specific case.

Here's a general solution:

import string

def make_rot_n(n):
 lc = string.ascii_lowercase
 uc = string.ascii_uppercase
 trans = string.maketrans(lc + uc,
                          lc[n:] + lc[:n] + uc[n:] + uc[:n])
 return lambda s: string.translate(s, trans)

rot13 = make_rot_n(13)

rot13('foobar')
# 'sbbone'



回答5:


From the module this.py (import this).

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print "".join([d.get(c, c) for c in s])



回答6:


As of Python 3.1, string.translate and string.maketrans no longer exist. However, these methods can be used with bytes instead.

Thus, an up-to-date solution directly inspired from Paul Rubel's one, is:

rot13 = bytes.maketrans(
    b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
    b"nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM")
b'Hello world!'.translate(rot13)

Conversion from string to bytes and vice-versa can be done with the encode and decode built-in functions.




回答7:


Try this:

import codecs
codecs.encode("text to be rot13()'ed", "rot_13")



回答8:


In python-3 the str-codec that @amber mentioned has moved to codecs standard-library:

> import codecs
> codecs.encode('foo', 'rot13')
sbb



回答9:


The following function rot(s, n) encodes a string s with ROT-n encoding for any integer n, with n defaulting to 13. Both upper- and lowercase letters are supported. Values of n over 26 or negative values are handled appropriately, e.g., shifting by 27 positions is equal to shifting by one position. Decoding is done with invrot(s, n).

import string

def rot(s, n=13):
    '''Encode string s with ROT-n, i.e., by shifting all letters n positions.
    When n is not supplied, ROT-13 encoding is assumed.
    '''
    upper = string.ascii_uppercase
    lower = string.ascii_lowercase
    upper_start = ord(upper[0])
    lower_start = ord(lower[0])
    out = ''
    for letter in s:
        if letter in upper:
            out += chr(upper_start + (ord(letter) - upper_start + n) % 26)
        elif letter in lower:
            out += chr(lower_start + (ord(letter) - lower_start + n) % 26)
        else:
            out += letter
    return(out)

def invrot(s, n=13):
    '''Decode a string s encoded with ROT-n-encoding
    When n is not supplied, ROT-13 is assumed.
    '''
    return(rot(s, -n))



回答10:


A one-liner to rot13 a string S:

S.translate({a : a + (lambda x: 1 if x>=0 else -1)(77 - a) * 13 for a in range(65, 91)})



回答11:


For arbitrary values, something like this works for 2.x

from string import ascii_uppercase as uc, ascii_lowercase as lc, maketrans                                                                                                            

rotate = 13 # ROT13                                                                    
rot = "".join([(x[:rotate][::-1] + x[rotate:][::-1])[::-1] for x in (uc,lc)])   

def rot_func(text, encode=True):                                                
    ascii = uc + lc                                                             
    src, trg = (ascii, rot) if encode else (rot, ascii)                         
    trans = maketrans(src, trg)                                                 
    return text.translate(trans)                                                

text = "Text to ROT{}".format(rotate)                                           
encode = rot_func(text)                                                         
decode = rot_func(encode, False)



回答12:


This works for uppercase and lowercase. I don't know how elegant you deem it to be.

def rot13(s):
    rot=lambda x:chr(ord(x)+13) if chr(ord(x.lower())+13).isalpha()==True else chr(ord(x)-13)
    s=[rot(i) for i in filter(lambda x:x!=',',map(str,s))]
    return ''.join(s)



回答13:


You can support uppercase letters on the original code posted by Mr. Walter by alternating the upper case and lower case letters.

chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"

If you notice the index of the uppercase letters are all even numbers while the index of the lower case letters are odd.

  • A = 0 a = 1,
  • B = 2, b = 3,
  • C = 4, c = 4,
  • ...

This odd-even pattern allows us to safely add the amount needed without having to worry about the case.

trans = chars[26:] + chars[:26]

The reason you add 26 is because the string has doubled in letters due to the upper case letters. However, the shift is still 13 spaces on the alphabet.

The full code:

def rot13(s):
    chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
    trans = chars[26:]+chars[:26]
    rot_char = lambda c: trans[chars.find(c)] if chars.find(c) > -1 else c
    return ''.join(rot_char(c) for c in s)

OUTPUT (Tested with python 2.7):

print rot13("Hello World!") --> Uryyb Jbeyq!



回答14:


def rot13(s):
    lower_chars = ''.join(chr(c) for c in range (97,123)) #ASCII a-z
    upper_chars = ''.join(chr(c) for c in range (65,91)) #ASCII A-Z
    lower_encode = lower_chars[13:] + lower_chars[:13] #shift 13 bytes
    upper_encode = upper_chars[13:] + upper_chars[:13] #shift 13 bytes
    output = "" #outputstring
    for c in s:
        if c in lower_chars:
                output = output + lower_encode[lower_chars.find(c)]
        elif c in upper_chars:
            output = output + upper_encode[upper_chars.find(c)]
        else:
            output = output + c
    return output

Another solution with shifting. Maybe this code helps other people to understand rot13 better. Haven't tested it completely.




回答15:


Interesting exercise ;-) i think i have the best solution because:

  1. no modules needed, uses only built-in functions --> no deprecation
  2. it can be used as a one liner
  3. based on ascii, no mapping dicts/strings etc.

Python 2 & 3 (probably Python 1):

def rot13(s):
    return ''.join([chr(ord(n) + (13 if 'Z' < n < 'n' or n < 'N' else -13)) if n.isalpha() else n for n in s])

def rot13_verbose(s):
    x = []
    for n in s:
        if n.isalpha():
            # 'n' is the 14th character in the alphabet so if a character is bigger we can subtract 13 to get rot13
            ort = 13 if 'Z' < n < 'n' or n < 'N' else -13
            x.append(chr(ord(n) + ort))
        else:
            x.append(n)
    return ''.join(x)



# crazy .min version (99 characters) disclaimer: not pep8 compatible^

def r(s):return''.join([chr(ord(n)+(13if'Z'<n<'n'or'N'>n else-13))if n.isalpha()else n for n in s])



回答16:


from string import maketrans, lowercase, uppercase

def rot13(message):
   lower = maketrans(lowercase, lowercase[13:] + lowercase[:13])
   upper = maketrans(uppercase, uppercase[13:] + uppercase[:13])
   return message.translate(lower).translate(upper)



回答17:


I found this post when I started wondering about the easiest way to implement rot13 into Python myself. My goals were:

  • Works in both Python 2.7.6 and 3.3.
  • Handle both upper and lower case.
  • Not use any external libraries.

This meets all three of those requirements. That being said, I'm sure it's not winning any code golf competitions.

def rot13(string):
    CLEAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
    ROT13 = 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'
    TABLE = {x: y for x, y in zip(CLEAR, ROT13)}

    return ''.join(map(lambda x: TABLE.get(x, x), string))



if __name__ == '__main__':
    CLEAR = 'Hello, World!'
    R13 = 'Uryyb, Jbeyq!'

    r13 = rot13(CLEAR)
    assert r13 == R13

    clear = rot13(r13)
    assert clear == CLEAR

This works by creating a lookup table and simply returning the original character for any character not found in the lookup table.

Update

I got to worrying about someone wanting to use this to encrypt an arbitrarily-large file (say, a few gigabytes of text). I don't know why they'd want to do this, but what if they did? So I rewrote it as a generator. Again, this has been tested in both Python 2.7.6 and 3.3.

def rot13(clear):
    CLEAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
    ROT13 = 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'
    TABLE = {x: y for x, y in zip(CLEAR, ROT13)}

    for c in clear:
        yield TABLE.get(c, c)



if __name__ == '__main__':
    CLEAR = 'Hello, World!'
    R13 = 'Uryyb, Jbeyq!'

    r13 = ''.join(rot13(CLEAR))
    assert r13 == R13

    clear = ''.join(rot13(r13))
    assert clear == CLEAR



回答18:


I couldn't leave this question here with out a single statement using the modulo operator.

def rot13(s):
    return ''.join([chr(x.islower() and ((ord(x) - 84) % 26) + 97
                        or x.isupper() and ((ord(x) - 52) % 26) + 65
                        or ord(x))
                    for x in s])

This is not pythonic nor good practice, but it works!

>> rot13("Hello World!")
Uryyb Jbeyq!



回答19:


You can also use this also

def n3bu1A(n):
    o=""
    key = {
       'a':'n', 'b':'o', 'c':'p', 'd':'q', 'e':'r', 'f':'s', 'g':'t', 'h':'u', 
       'i':'v', 'j':'w', 'k':'x', 'l':'y', 'm':'z', 'n':'a', 'o':'b', 'p':'c', 
       'q':'d', 'r':'e', 's':'f', 't':'g', 'u':'h', 'v':'i', 'w':'j', 'x':'k',
       'y':'l', 'z':'m', 'A':'N', 'B':'O', 'C':'P', 'D':'Q', 'E':'R', 'F':'S', 
       'G':'T', 'H':'U', 'I':'V', 'J':'W', 'K':'X', 'L':'Y', 'M':'Z', 'N':'A', 
       'O':'B', 'P':'C', 'Q':'D', 'R':'E', 'S':'F', 'T':'G', 'U':'H', 'V':'I', 
       'W':'J', 'X':'K', 'Y':'L', 'Z':'M'}
    for x in n:
        v = x in key.keys()
        if v == True:
            o += (key[x])   
        else:
            o += x
    return o

Yes = n3bu1A("N zhpu fvzcyre jnl gb fnl Guvf vf zl Zragbe!!")
print(Yes)



回答20:


Short solution:

def rot13(text):
    return "".join([x if ord(x) not in range(65, 91)+range(97, 123) else
            chr(((ord(x)-97+13)%26)+97) if x.islower() else
            chr(((ord(x)-65+13)%26)+65) for x in text])


来源:https://stackoverflow.com/questions/3269686/short-rot13-function-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!