469,271 Members | 1,435 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,271 developers. It's quick & easy.

rot13 in a more Pythonic style?

I'm trying to write rot13, but to do it in a better and more Pythonic
style than I'm currrently using. What would you reckon to the
following pretty ugly thing? How would you improve it? In
particular, I don't like the way a three-way selection is done by
nesting two binary selections. Also I dislike stating the same
algorithm twice, but can't see how to parameterise them neatly.

Yes, I know of .encode() and .translate().
No, I don't actually need rot13 itself, it's just a convenient
substitute example for the real job-specific task.
No, I don't have to do it with lambdas, but it would be nice if the
final function was a lambda.
#!/bin/python
import string

lc_rot13 = lambda c : (chr((ord(c) - ord('a') + 13) % 26 + ord('a')))

uc_rot13 = lambda c : (chr((ord(c) - ord('A') + 13) % 26 + ord('A')))

c_rot13 = lambda c : (((c, uc_rot13(c)) [c in
'ABCDEFGHIJKLMNOPQRSTUVWXYZ']), lc_rot13(c) )[c in
'abcdefghijklmnopqrstuvwxyz']

rot13 = lambda s : string.join([ c_rot13(c) for c in s ],'')
print rot13( 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt' )

Feb 14 '07 #1
16 2318
You could try "some_string".encode('rot_13')

Feb 14 '07 #2
On 2007-02-14, Andy Dingley <di*****@codesmiths.comwrote:
I'm trying to write rot13, but to do it in a better and more
Pythonic style than I'm currrently using. What would you
reckon to the following pretty ugly thing? How would you
improve it? In particular, I don't like the way a three-way
selection is done by nesting two binary selections. Also I
dislike stating the same algorithm twice, but can't see how to
parameterise them neatly.

Yes, I know of .encode() and .translate().
str.translate is what I'd do.

import string
rot13table = string.maketrans(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW XYZ',
'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJ KLM')

print 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt'.translate(rot13table)
No, I don't actually need rot13 itself, it's just a convenient
substitute example for the real job-specific task. No, I don't
have to do it with lambdas, but it would be nice if the final
function was a lambda.
How would it being a lambda help you?

--
Neil Cerutti
Feb 14 '07 #3
Andy Dingley wrote:
I'm trying to write rot13, but to do it in a better and more Pythonic
style than I'm currrently using. What would you reckon to the
following pretty ugly thing? How would you improve it? In
particular, I don't like the way a three-way selection is done by
nesting two binary selections. Also I dislike stating the same
algorithm twice, but can't see how to parameterise them neatly.

Yes, I know of .encode() and .translate().
No, I don't actually need rot13 itself, it's just a convenient
substitute example for the real job-specific task.
No, I don't have to do it with lambdas, but it would be nice if the
final function was a lambda.
#!/bin/python
import string

lc_rot13 = lambda c : (chr((ord(c) - ord('a') + 13) % 26 + ord('a')))

uc_rot13 = lambda c : (chr((ord(c) - ord('A') + 13) % 26 + ord('A')))

c_rot13 = lambda c : (((c, uc_rot13(c)) [c in
'ABCDEFGHIJKLMNOPQRSTUVWXYZ']), lc_rot13(c) )[c in
'abcdefghijklmnopqrstuvwxyz']

rot13 = lambda s : string.join([ c_rot13(c) for c in s ],'')
print rot13( 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt' )
Well first of all, for me (personal) being Pythonic means that I should
separate the logic and variables, in this case there is the rotation
mechanism and the variable with the amount it should rotate.
Then of course the letters case is something I consider as a state of
the letter itself, the meaning of the letter doesn't change.
And being a sucker for dictionaries I use them a lot

So with that in mind I would write a class like this:
###
class Rot(object):
def __init__(self,amount = 13):
self.__alpha = 'abcdefghijklmnopqrstuvwxyz'
self.__amount = amount
self.__index_string = dict()
self.__crypt_index_string = dict()
self.__string_index = dict()
self.__crypt_string_index = dict()
self.__position = 0

self.__create_dicts()
def __cypher(self,number):
alpha_len = len(self.__alpha)
rotation_overflow = alpha_len - self.__amount
new_number = None

if number rotation_overflow:
new_number = number - self.__amount

else:
new_number = self.__position + self.__amount

return(new_number)
def __create_dicts(self):
for letter in self.__alpha:
self.__position += 1

self.__index_string[self.__position] = letter
self.__crypt_index_string[self.__cypher(self.__position)] =
letter

self.__string_index[letter] = self.__position
self.__crypt_string_index[letter] =
self.__cypher(self.__position)
def encrypt(self,text):
text_list = list()
letter_capital = None

for letter in text:
letter_capital = letter.isupper()
letter = letter.lower()

if letter not in self.__alpha:
text_list.append(letter)

else:
position_plain = self.__string_index[letter]
letter_crypt = self.__crypt_index_string[position_plain]

if letter_capital:
letter_crypt = letter_crypt.upper()

text_list.append(letter_crypt)

return("".join(text_list))
def decrypt(self,text):
text_list = list()
letter_capital = None

for letter in text:
letter_capital = letter.isupper()
letter = letter.lower()

if letter not in self.__alpha:
text_list.append(letter)

else:
position_crypt = self.__crypt_string_index[letter]
letter_plain = self.__index_string[position_crypt]

if letter_capital:
letter_plain = letter_plain.upper()

text_list.append(letter_plain)

return("".join(text_list))
###

Testing if it works:
>>rot13.decrypt(rot13.encrypt("This is a TEST"))
'This is a TEST'

--
mph

Feb 14 '07 #4
On 14 Feb, 16:23, Neil Cerutti <horp...@yahoo.comwrote:
str.translate is what I'd do.
That's what I hope to do too, but it might not be possible (for the
live, complex example). It looks as if I have to make a test, then
process the contents of the code differently depending. There might
well be a translation inside this, but I think I still have to have an
explicit 3-way switch in there.
How would it being a lambda help you?
I'm going to use it in a context where that would make for cleaner
code. There's not much in it though.

I still don't understand what a lambda is _for_ in Python. I know what
they are, I know what the alternatives are, but I still haven't found
an instance where it permits something novel to be done that couldn't
be done otherwise (if maybe not so neatly).

Feb 14 '07 #5
En Wed, 14 Feb 2007 14:04:17 -0300, Andy Dingley <di*****@codesmiths.com>
escribió:
I still don't understand what a lambda is _for_ in Python. I know what
they are, I know what the alternatives are, but I still haven't found
an instance where it permits something novel to be done that couldn't
be done otherwise (if maybe not so neatly).
A lambda is a shorthand for a simple anonymous function. Any lambda can be
written as a function:

lambda args: expression

is the same as:

def __anonymous(args): return expression

(but the inverse is not true; lambda only allows a single expression in
the function body).

Except for easy event binding in some GUIs, deferred argument evaluation,
and maybe some other case, the're not used much anyway. Prior common usage
with map and filter can be replaced by list comprehensions (a lot more
clear, and perhaps as fast - any benchmark?)

--
Gabriel Genellina

Feb 14 '07 #6
On Feb 14, 9:04 am, "Andy Dingley" <ding...@codesmiths.comwrote:
I still don't understand what a lambda is _for_ in Python.
Python supports functional programming to a certain extent, and
lambdas are part of this.

http://linuxgazette.net/109/pramode.html
I know what
they are, I know what the alternatives are, but I still haven't found
an instance where it permits something novel to be done that couldn't
be done otherwise (if maybe not so neatly).
Strictly speaking, you can live your whole life without using them.
There's always a procedural way of doing things, as well.

-Beej

Feb 14 '07 #7
"Andy Dingley" <di*****@codesmiths.comwrites:
I'm trying to write rot13, but to do it in a better and more Pythonic
style than I'm currrently using. What would you reckon to the
following pretty ugly thing? How would you improve it? In
particular, I don't like the way a three-way selection is done by
nesting two binary selections. Also I dislike stating the same
algorithm twice, but can't see how to parameterise them neatly.
It looks to me like a good place to use closure and dictionaries.
I would write it this way:

def rot(step):
import string
rot_char = lambda a,c,step=step: chr((((ord(c) - ord(a)) + step) % 26) + ord(a))
make_dict = lambda a,s: dict([(x, rot_char(a, x)) for x in s])
d = make_dict('a', string.ascii_lowercase)
d.update(make_dict('A', string.ascii_uppercase))
def f(s):
return "".join([d.get(c) or c for c in s])
return f
>>rot13 = rot(13)
rot13('Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt')
'Florix Grabundae, Splundig vur thrigg'
>>rot_13 = rot(-13)
rot_13('Florix Grabundae, Splundig vur thrigg')
'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt'

--
HTH,
Rob
Feb 14 '07 #8
"Andy Dingley" <di*****@codesmiths.comwrites:
I'm trying to write rot13, but to do it in a better and more Pythonic
style than I'm currrently using. What would you reckon to the
following pretty ugly thing? How would you improve it? In
particular, I don't like the way a three-way selection is done by
nesting two binary selections. Also I dislike stating the same
algorithm twice, but can't see how to parameterise them neatly.
I'm having a hard time understanding what you're getting at. Why
don't you describe the actual problem instead of the rot13 analogy.
Feb 14 '07 #9
Martin P. Hellwig
for me (personal) being Pythonic means that I should
separate the logic and variables, etc...
Well, for me me Pythonic means using built-in functionalities as much
as possible (like using encode("rot13") or translate), and to write
less code, (avoiding overgeneralizations from the start too). It means
other things too.

Bye,
bearophile

Feb 14 '07 #10
"Andy Dingley" <di*****@codesmiths.comwrites:
c_rot13 = lambdaf c : (((c, uc_rot13(c)) [c in
'ABCDEFGHIJKLMNOPQRSTUVWXYZ']), lc_rot13(c) )[c in
'abcdefghijklmnopqrstuvwxyz']
Oh, I see what you mean, you have separate upper and lower case maps
and you're asking how to select one in an expression. Pythonistas
seem to prefer using multiple statements:

def c_rot13(c):
if c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': return uc_rot13(c)
elif c in 'abcdefghijklmnopqrstuvwxyz': return lc_rot13(c)
return c

You could use the new ternary expression though:

c_rot13 = lambda c: \
uc_rot13(c) if c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' else \
(lc_rot13(c) if c in 'abcdefghijklmnopqrstuvwxyz' else \
c)

if I have that right.
Feb 14 '07 #11
be************@lycos.com wrote:
Martin P. Hellwig
>for me (personal) being Pythonic means that I should
separate the logic and variables, etc...

Well, for me me Pythonic means using built-in functionalities as much
as possible (like using encode("rot13") or translate), and to write
less code, (avoiding overgeneralizations from the start too). It means
other things too.

Bye,
bearophile
Yup, but I have a sever case of "NIH" especially if the question asked
is something more general then the example given :-)
However you are very much right, I reimplemented rot13 and translate in
a dull way here :-)

--
mph
Feb 14 '07 #12
On 14 Feb, 21:59, Paul Rubin <http://phr...@NOSPAM.invalidwrote:
Why don't you describe the actual problem instead of the rot13 analogy.
I don't know what the actual problem is! I need to perform a complex
mapping between "old style" structured identifiers and "new style"
structured identifers. As the original specification was never thought
through or written down anywhere, I'm now having to try and reverse-
engineer from 5 years of collected inconsistent practice. So far I
have about four pages of BNF to describe things and I'm still not sure
what's accurate, what's inaccurate spec and what's merely an error in
practice. Hopefully there's a neat little structure underlying it all
and a few typos I can merely ignore, but probably it really is just an
inconsistent structure that needs a lot of explicit tests around the
corner-cases to make sense of.

rot13 isn't the issue here, and I already know how to use .translate()
What I'm after is a tutorial of my Python coding style for an example
that's quite similar to the rot13 case. Your previous posting was
very helpful here.

Feb 15 '07 #13
On Feb 14, 11:46 am, "Gabriel Genellina" <gagsl...@yahoo.com.ar>
wrote:
En Wed, 14 Feb 2007 14:04:17 -0300, Andy Dingley <ding...@codesmiths.com>
escribió:
I still don't understand what a lambda is _for_ in Python. I know what
they are, I know what the alternatives are, but I still haven't found
an instance where it permits something novel to be done that couldn't
be done otherwise (if maybe not so neatly).

A lambda is a shorthand for a simple anonymous function. Any lambda can be
written as a function:

lambda args: expression

is the same as:

def __anonymous(args): return expression

(but the inverse is not true; lambda only allows a single expression in
the function body).

Except for easy event binding in some GUIs, deferred argument evaluation,
and maybe some other case, the're not used much anyway. Prior common usage
with map and filter can be replaced by list comprehensions (a lot more
clear, and perhaps as fast - any benchmark?)

--
Gabriel Genellina
They are still useful for reduce(), which has no listcomp equivalent
that I know of.

Feb 15 '07 #14
On 15 Feb, 17:55, Dennis Lee Bieber <wlfr...@ix.netcom.comwrote:
Sounds more like a case for a parser/lexer wherein the emitted "code
tokens" are the "new style" identifiers...
8-( I'm trying not to think about that....

Fortunately I don't think it's _quite_ that bad.

Feb 15 '07 #15
On Fri, 16 Feb 2007 04:53:23 +0000, Dennis Lee Bieber wrote:
On 15 Feb 2007 11:10:53 -0800, "Andy Dingley" <di*****@codesmiths.com>
declaimed the following in comp.lang.python:
>>
Fortunately I don't think it's _quite_ that bad.

Possibly not, but that description of the problem would likely have
gotten more applicable help than a debate on the merits of
reimplementing translate().

The Original Poster did say in his first post that he knew about translate
and encode and he wasn't looking for those solutions:

[quote]
Yes, I know of .encode() and .translate().
No, I don't actually need rot13 itself, it's just a convenient
substitute example for the real job-specific task.
[end quote]

Perhaps rot13 wasn't the best choice in the world, but how was Andy to
know people would answer his post without reading it in full?

Oh wait, this is Usenet...

*wink*
--
Steven.

Feb 16 '07 #16
On 14 Feb, 20:06, "Beej" <b...@beej.uswrote:
http://linuxgazette.net/109/pramode.html
Thanks, that's a _really_ interesting link (Oh, I need to learn
Scheme!)

My code now looks like this, which I'm starting to feel much happier
about in a functional sense.
c_rot = lambda c, chars : (chr((ord(c) - ord(chars[0]) +
(len(chars) // 2)) % len(chars) + ord(chars[0])))

c_rot13 = lambda c : (((c, \
c_rot(c, string.ascii_uppercase)) [c in string.ascii_uppercase]),
\
c_rot(c, string.ascii_lowercase)) [c in string.ascii_lowercase]

rot13 = lambda s : string.join([ c_rot13(c) for c in s ],'')

I also considered this, but don't trust it as it relies on the two
sets being mutually disjoint between their inputs and outputs.

qc_rot = lambda c, chars : (c, c_rot(c, chars)) [c in chars]
c_rot13 = lambda c : (qc_rot( qc_rot(c, string.ascii_lowercase),
string.ascii_uppercase))
Feb 16 '07 #17

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

12 posts views Thread by Nickolay Kolev | last post: by
15 posts views Thread by Eirik | last post: by
5 posts views Thread by yxq | last post: by
3 posts views Thread by andrew.fabbro | last post: by
4 posts views Thread by Carl J. Van Arsdall | last post: by
20 posts views Thread by krypto.wizard | last post: by
14 posts views Thread by Pythor | last post: by
11 posts views Thread by Hussein B | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.