views:

140

answers:

4

A multi-line string, e.g.

abc 123
456 def

wanted result (ordinal + 2):

cde 345
678 fgh

if I use:

text = "abc 123\n456 def"
add2=''.join(chr(ord(c)+2) for c in text)
print text
print add2

the space and \r \n will also be replaced, how can I add the exception of not including space, \r or \n in the 2nd line of code.

p.s. it's follow up to this question.

+1  A: 
add2 = ''.join(chr(ord(c) + 2) if c not in "\n\r " else c for c in text)
Roger Pate
+2  A: 

You can simply check if the character is alphanumeric and keep the original character otherwise:

add2 = ''.join(chr(ord(c)+2) if c.isalnum() else c for c in text)

Please note that applying this to some characters (such as 'y', 'z', '9', '0' etc) might not yield what you expect. I.e., 'y' will not become 'a', but '{'.

rbp
You forgot the parens to call isalnum, but why not check the actual characters asked for? (newline, carriage return, and space)
Roger Pate
Yeah, I had just noticed about the parens :) I was trying to be a bit more generic, since apparently what he wants is to shift alphanumeric characters, and skip the rest (like punctuation etc).
rbp
+2  A: 

Your other question suggests that you might be translating a very long string (a PDF file). In that case, using the string translate method will be quicker than doing a character-by-character for-loop over the string:

test.py:

import string

infile='filename.pdf'
outfile='newfile.pdf'

with open(infile,'r') as f:
    text=f.read()

def using_translate():
    start_chars=''.join(chr(n) for n  in range(256) if not chr(n).isspace())
    end_chars=''.join(chr((ord(c)+2)%256) for c in start_chars)
    table = string.maketrans(start_chars,end_chars)
    return text.translate(table)

def using_for_c_in_text():
    return ''.join(chr((ord(c) + 2)%256) if not c.isspace() else c for c in text)

This shows the results of a timeit run using a 1M pdf file:

# % python -mtimeit -s"import test" "test.using_for_c_in_text()"
# 10 loops, best of 3: 821 msec per loop
# % python -mtimeit -s"import test" "test.using_translate()"
# 100 loops, best of 3: 4.36 msec per loop

PS: Many answers (including mine at one point) used chr(ord(c) + 2). This throws a TypeError if ord(c)+2>=256. To avoid the TypeError, you could use chr((ord(c) + 2)%256).

unutbu
ohho
@Horace: I've altered my answer to address your comment.
unutbu
chr((ord(c) + 2)%256) is sweet.
ohho
to be safe, I add +256, so it becomes (ord(c) + 256 + diff) % 256 as diff maybe a -ve number
ohho
+2  A: 

slower than @Roger's solution but filters all whitespace:

>>> text = "abc 123\n456 def"
>>> ''.join(chr(ord(c) + 2) if not c.isspace() else c for c in text)
'cde 345\n678 fgh'

same as above but only bumps up alphanumerics:

>>> text = "abc 123\n456 def"
>>> ''.join(chr(ord(c) + 2) if c.isalnum() else c for c in text)
'cde 345\n678 fgh'
wescpy