Fonction rot13 courte-Python [fermé]
Je suis à la recherche d'une fonction rot13 courte et cool en 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 faire mieux? Par exemple, soutenir les caractères majuscules.
20 réponses
Voici une solution maketrans / translate
import string
rot13 = string.maketrans(
"ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",
"NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
string.translate("Hello World!", rot13)
# 'Uryyb Jbeyq!'
, C'est très simple:
>>> import codecs
>>> codecs.encode('foobar', 'rot_13')
'sbbone'
>>> 'foobar'.encode('rot13')
'sbbone'
(j'ai entendu des rumeurs que cela ne fonctionne pas dans Python 3.x cependant.)
Le maketrans
et translate
fonctions dans le string
module sont à portée de main pour ce genre 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'
Du 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])
, Comme de Python 3.1, string.translate
et string.maketrans
n'existent 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)
Conversion à partir de string
à bytes
et vice-versa peut être fait avec l'encode
et decode
les fonctions intégrées.
Essayez ceci:
import codecs
codecs.encode("text to be rot13()'ed", "rot_13")
En python-3 le str
-codec @orange mentionné a déménagé à codecs
standard-bibliothèque:
> import codecs
> codecs.encode('foo', 'rot13')
sbb
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)
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)
Vous pouvez prendre en charge les majuscules sur le code original posté par M. Walter en alternant les majuscules et les minuscules.
chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
Si vous remarquez l'index des lettres majuscules sont tous des nombres pairs, tandis que l'indice des lettres minuscules sont impairs.
- A = 0 a = 1,
- B = 2, b = 3,
- C = 4, c = 4,
- ...
Ce modèle pair-impair nous permet d'ajouter en toute sécurité la quantité nécessaire sans avoir à se soucier de l'affaire.
trans = chars[26:] + chars[:26]
La raison pour laquelle vous ajoutez 26 est parce que la chaîne a doublé en lettres en raison des lettres majuscules. Cependant, le décalage est toujours 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ée avec Python 2.7):
print rot13("Hello World!") --> Uryyb Jbeyq!
La fonction suivante rot(s, n)
code une chaîne s
avec un codage ROT-n
pour tout entier n
, avec n
par défaut à 13. Les lettres majuscules et minuscules sont prises en charge. Des valeurs de n
supérieures à 26 ou des valeurs négatives sont traitées de manière appropriée, par exemple, le déplacement de 27 positions est égal au déplacement 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))
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)})
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éplacement. Peut-être que ce code aide les autres à mieux comprendre rot13. N'ai pas testé complètement.
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)
Exercice intéressant ; -) je pense avoir la meilleure solution car:
- aucun module nécessaire, utilise uniquement des fonctions intégrées -- > aucune dépréciation
- , il peut être utilisé comme une doublure
- basé sur ascii, pas de mappage dicts / strings etc.
Python 2 et 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])
J'ai trouvé ce post quand j'ai commencé à me poser des questions sur la façon la plus simple de mettre en œuvre
rot13
en Python moi-même. Mes objectifs étaient:
- fonctionne à la fois en python 2.7.6 et 3.3.
- gère les majuscules et les minuscules.
- N'utilise aucune bibliothèque externe.
Cela répond à ces trois exigences. Cela étant dit, je suis sûr qu'il ne gagne pas de compétitions de golf de 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 __name__ == '__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.
Mettre à jour
Je me suis inquiété de quelqu'un qui voulait l'utiliser pour chiffrer un fichier arbitrairement volumineux (disons, quelques gigaoctets de texte). Je ne sais pas pourquoi ils voudraient faire ça, mais si c'était le cas? Donc je l'ai réécrit comme un générateur. Encore une fois, cela a été testé dans 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 __name__ == '__main__':
CLEAR = 'Hello, World!'
R13 = 'Uryyb, Jbeyq!'
r13 = ''.join(rot13(CLEAR))
assert r13 == R13
clear = ''.join(rot13(r13))
assert clear == CLEAR
Je ne pouvais pas laisser cette question ici sans une seule instruction 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 pythonique ni bonne pratique, mais ça marche!
>> rot13("Hello World!")
Uryyb Jbeyq!
Vous pouvez également l'utiliser aussi
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)
Solution courte:
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])