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