aboutsummaryrefslogtreecommitdiffstats
path: root/src/shorturls/baseconv.py
blob: 1b4fd15539d86622045a4e88daf2f2d550308cb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""
Convert numbers from base 10 integers to base X strings and back again.

Original: http://www.djangosnippets.org/snippets/1431/

Sample usage:

>>> base20 = BaseConverter('0123456789abcdefghij')
>>> base20.from_decimal(1234)
'31e'
>>> base20.to_decimal('31e')
1234
"""

class BaseConverter(object):
    decode_mapping = {}
    
    def __init__(self, digits):
        self.digits = digits
        self.length = len(digits)
    
    def from_decimal(self, i):
        if i < 0:
            i, neg = -i, 1
        else:
            neg = 0
        enc = ''
        while i >= self.length:
            i, mod = divmod(i, self.length)
            enc = self.digits[mod] + enc
        enc = self.digits[i] + enc
        if neg:
            enc = '-' + enc
        return enc
    
    def to_decimal(self, s):
        if self.decode_mapping:
            new = ''
            for digit in s:
                if digit in self.decode_mapping:
                    new += self.decode_mapping[digit]
                else:
                    new += digit
            s = new
        if str(s)[0] == '-':
            s, neg = str(s)[1:], 1
        else:
            neg = 0
        decoded = 0
        multi = 1
        while len(s) > 0:
            decoded += multi * self.digits.index(s[-1:])
            multi = multi * self.length
            s = s[:-1]
        if neg:
            decoded = -decoded
        return decoded
    
bin = BaseConverter('01')
hexconv = BaseConverter('0123456789ABCDEF')
base62 = BaseConverter(
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
)

class Base32Converter(BaseConverter):
    """
    http://www.crockford.com/wrmg/base32.html
    """
    decode_mapping = {
        'o': '0',
        'i': '1',
        'l': '1',
    }
    
    def __init__(self):
        super(Base32Converter, self).__init__('0123456789abcdefghjkmnpqrstvwxyz')
    
    def to_decimal(self, s):
        return super(Base32Converter, self).to_decimal(s.lower())

base32 = Base32Converter()

if __name__ == '__main__':
    import doctest
    doctest.testmod()