web-dev-qa-db-fra.com

Fonction rot13 courte - Python

Je recherche une fonction rot13 courte et cool dans Python ;-) J'ai écrit cette fonction:

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 ) 

Quelqu'un peut-il l'améliorer? Par exemple, prendre en charge les caractères majuscules.

59
svenwltr

Voici une solution maketrans/translate

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

C'est très simple:

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

Cela fonctionne sur Python 2 (mais pas Python 3):

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

Les fonctions maketrans et translate du module string sont pratiques pour ce type de chose. Bien sûr, la méthode encode dans la réponse d'Amber est encore plus pratique pour ce cas spécifique.

Voici une solution générale:

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'
21
ars

Depuis le 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])
10
Artur Gaspar

À partir de Python 3.1, string.translate et string.maketrans n'existe plus. Cependant, ces méthodes peuvent être utilisées avec bytes à la place.

Ainsi, une solution à jour directement inspirée de celle de Paul Rubel, est:

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

La conversion de string en bytes et vice-versa peut être effectuée avec encode et decode = fonctions intégrées.

8
bbc

Essaye ça:

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

En python-3, le codec str- mentionné par @amber a été déplacé vers codecs standard-library:

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

La fonction suivante rot(s, n) code une chaîne s avec l'encodage ROT - n pour tout entier n, avec n avec 13 par défaut. Les lettres majuscules et minuscules sont prises en charge. Les valeurs de n supérieures à 26 ou les valeurs négatives sont gérées de manière appropriée, par exemple, un décalage de 27 positions est égal au décalage d'une position. Le décodage se fait avec 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))
4
jeroen

Un one-liner pour rot13 une chaîne S:

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

Cela fonctionne pour les majuscules et les minuscules. Je ne sais pas à quel point vous le jugez élégant.

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)
2
Eratosthenes

Pour les valeurs arbitraires, quelque chose comme ça fonctionne pour 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)
2
user1543747

Vous pouvez prendre en charge les lettres majuscules sur le code d'origine publié par M. Walter en alternant les majuscules et les minuscules.

chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"

Si vous remarquez que l'index des lettres majuscules sont tous des nombres pairs alors que l'index des lettres minuscules est impair.

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

Ce motif pair-impair nous permet d'ajouter en toute sécurité la quantité nécessaire sans avoir à vous soucier de l'affaire.

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

La raison pour laquelle vous ajoutez 26 est que la chaîne a doublé en lettres en raison des majuscules. Cependant, le décalage est toujours de 13 espaces sur l'alphabet.

Le code complet:

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)

SORTIE (Testé avec python 2.7):

print rot13("Hello World!") --> Uryyb Jbeyq!
2
Diaz
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

Une autre solution avec le décalage. Peut-être que ce code aide les autres à mieux comprendre rot13. Je ne l'ai pas testé complètement.

1
DeaD_EyE

Exercice intéressant ;-) je pense avoir la meilleure solution car:

  1. aucun module nécessaire, utilise uniquement des fonctions intégrées -> pas de dépréciation
  2. il peut être utilisé comme une doublure
  3. basé sur ascii, pas de mappage de dict/chaînes, etc.

Python 2 & 3 (probablement 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])
0
yamm
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)
0
user847988

Vous pouvez également l'utiliser également

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)
0
Francis Bangura

J'ai trouvé ce message lorsque j'ai commencé à me poser des questions sur la manière la plus simple de mettre en œuvre rot13 en Python moi-même. Mes objectifs étaient:

  • Fonctionne dans les deux Python 2.7.6 et 3.3.
  • Manipulez les majuscules et les minuscules.
  • N'utilisez aucune bibliothèque externe.

Cela répond à ces trois exigences. Cela étant dit, je suis sûr qu'il ne remporte aucune compétition de golf à code.

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 __== '__main__':
    CLEAR = 'Hello, World!'
    R13 = 'Uryyb, Jbeyq!'

    r13 = rot13(CLEAR)
    assert r13 == R13

    clear = rot13(r13)
    assert clear == CLEAR

Cela fonctionne en créant une table de recherche et en renvoyant simplement le caractère d'origine pour tout caractère introuvable dans la table de recherche.

Mise à jour

Je devais m'inquiéter à propos de quelqu'un qui voulait l'utiliser pour crypter un fichier arbitrairement volumineux (disons, quelques gigaoctets de texte). Je ne sais pas pourquoi ils voudraient faire ça, mais si c'était le cas? Je l'ai donc réécrit en générateur. Encore une fois, cela a été testé dans les deux Python 2.7.6 et 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 __== '__main__':
    CLEAR = 'Hello, World!'
    R13 = 'Uryyb, Jbeyq!'

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

    clear = ''.join(rot13(r13))
    assert clear == CLEAR
0
Doug R.

Je ne pouvais pas laisser cette question ici sans une seule déclaration en utilisant l'opérateur modulo.

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])

C'est pas Pythonic ni une bonne pratique, mais ça marche!

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