views:

70

answers:

6

I have a string. It looks like s = 'e6b693e6a0abe699ab'.

I want to put a percent sign in front of every pair of characters, so percentEncode(s) == '%e6%b6%93%e6%a0%ab%e6%99%ab'.

What's a good way of writing percentEncode(s)?

(Note, I don't care that unreserved characters aren't converted into ASCII.)

I can think of big verbose ways of doing this, but I want something nice and simple, and while I'm fairly new to Python, I'd be suprised if Python can't do this nicely.

+2  A: 
>>> ''.join( "%"+i+s[n+1] for n,i in enumerate(s)  if n%2==0 )
'%e6%b6%93%e6%a0%ab%e6%99%ab'

Or using re

>>> import re
>>> re.sub("(..)","%\\1",s)
'%e6%b6%93%e6%a0%ab%e6%99%ab'
ghostdog74
I like the regex solution. You also found a bug in SO — before I edited it, the first method displayed as code in the JS preview, but as a quote in the server-rendered version.
David Johnstone
+2  A: 

Oh, you mean:

''.join(["%%%s" % pair for pair in [s[i:i+2] for i in range(0,len(s),2)]])

Though probably if you're doing this for url escaping or some such, there's a library function more appropriate to your use.

Edited to add -- since everyone loves a cute itertools solution:

>>> from itertools import izip, cycle
>>> its = iter(s)
>>> tups = izip(cycle('%'), its, its)
>>> ''.join(''.join(t) for t in tups)
'%e6%b6%93%e6%a0%ab%e6%99%ab'
tcarobruce
cycle('%') will provide the same thing, since '' are iterable.
kevpie
Thanks @kevpie, incorporated this.
tcarobruce
+1  A: 

use a Regex to the effect of /([0-9a-f]{2})/ig and replace with %\1

tobyodavies
+2  A: 

On the off chance that you are doing URL-encoding manually, you might want to read this blog post. It explains how to do this using the standard library's urllib module's quote_plus function.

intuited
+1  A: 

Just to be academic.

Trying to use as many iterators as possible.

s = 'e6b693e6a0abe699ab'

from itertools import islice, izip, cycle, chain

def percentEncode(s):
    percentChars = cycle('%')
    firstChars = islice(s,0,None, 2)
    secondChars = islice(s,1,None, 2)
    return ''.join(chain.from_iterable(izip(percentChars, firstChars, secondChars)))


if __name__ == '__main__':
     print percentEncode(s)

Thanks to @tcarobruce for the reminder to reuse the string iter.

s = 'e6b693e6a0abe699ab'

from itertools import islice, izip, cycle, chain

def percentEncode(s):
    iter_s = iter(s)
    return ''.join(chain.from_iterable(izip(cycle('%'), iter_s, iter_s)))

if __name__ == '__main__':
     print percentEncode(s)
kevpie
+1  A: 

Based on a comment of yours in the initial question, if starting from the initial string initial_s before its encoding into hex, you can have the result as:

def percent_encode(initial_s):
    return ''.join('%%%02x' % ord(c) for c in initial_s)

>>> percent_encode('hello')
'%68%65%6c%6c%6f'
ΤΖΩΤΖΙΟΥ