3 by Mike Crute (mcrute@gmail.com) on August 26, 2008
4 This code has been placed in the public domain.
6 This is just a simple module to do base36 encoding and decoding. Theoretically
7 you could use this for any base < 2 <= 36 && base != 32 but I only really need
8 to have base36 so its an exercise for the reader to implement other base
11 This won't work for base32 at least not if you want your output to work with other
12 base32 decoders because RFC4648 skips 0 and 1 (2-7A-Z) and this module doesn't
13 account for that. Bah...
15 The only reason I wrote this is because the other implementations of base
16 conversion relied upon hard coded lists of characters and that really
17 bothered me, plus didn't quite give me the flexibility I was looking for.
20 def _codec(str_in, base_from=36, base_to=10):
21 """Convert a number to/from a base less than or equal to 36.
22 Converts a string or number to or from a base without using static
26 ASCII = { "0": 48, "9": 57, "A": 65, "Z": 90 }
28 # There are 8 characters between 9 and A
29 from_digits = [chr(x) for x in range(ASCII["0"], ASCII["9"] + 8 + base_from)
30 if (x >= ASCII["0"] and x <= ASCII["9"]) or
31 (x >= ASCII["A"] and x <= ASCII["Z"])][:base_from]
33 to_digits = [chr(x) for x in range(ASCII["0"], ASCII["9"] + 8 + base_to)
34 if (x >= ASCII["0"] and x <= ASCII["9"]) or
35 (x >= ASCII["A"] and x <= ASCII["Z"])][:base_to]
38 for digit in str(str_in).upper():
39 x = x * len(from_digits) + from_digits.index(digit)
42 # This is going to assemble our number in reverse order
43 # so we'll have to fix it before we return it
45 result += to_digits[x % len(to_digits)]
51 def base36encode(str_in):
52 """Base36 encode a base10 number.
54 return _codec(str_in, 10, 36)
56 def base36encode(str_in):
57 """Get a base10 number for a base36 number.
59 return long(_codec(str_in, 36, 10))