zvoase (owner)

Revisions

gist: 20925 Download_button fork
public
Public Clone URL: git://gist.github.com/20925.git
Embed All Files: show embed
baseconversion.py #
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import copy
 
 
class Base(object):
    
    def __init__(self, words, name=''):
        self.__words = words
        if not name:
            name = 'base%d' % (self.length,)
        self.name = name
    
    def __repr__(self):
        return 'Base(%r, %r)' % (self.words, self.name)
    
    def __get_words(self):
        return self.__words
    
    def __get_length(self):
        return len(self.words)
    
    def is_valid(self, values):
        return set(values).issubset(set(self.words))
    
    words = property(__get_words)
    length = property(__get_length)
 
 
class Number(object):
    
    def __init__(self, base, values=[]):
        assert base.is_valid(values), (
            'Invalid number for base %r: %r' % (base, values))
        self.__base = base
        self.__indices = map(self.base.words.index, values)
    
    def __repr__(self):
        return 'Number(%r, %r)' % (self.base.name, self.values)
    
    def __str__(self):
        if hasattr(self.base, 'format'):
            return self.base.format(self)
        return ''.join(map(str, self.values))
    
    def zfill(self, length):
        s = str(self)
        if len(s) < length:
            return ''.join(
                self.base.words[0] for i in xrange(length - len(s))) + s
        return s
    
    @classmethod
    def from_decimal(cls, base, decimal):
        new = Number(DECIMAL, str(decimal))
        new.base = base
        return new
    
    def __get_base(self):
        return self.__base
    
    def __set_base(self, base):
        old_decimal = copy.copy(self.decimal)
        self.__base = base
        self.decimal = old_decimal
    
    def __get_decimal(self):
        decimal = 0
        for index, value in enumerate(reversed(self.__indices)):
            decimal += value * (self.base.length ** index)
        return decimal
 
    def __set_decimal(self, decimal):
        indices = []
        number = copy.copy(decimal)
        while number:
            indices.insert(0, number % self.base.length)
            number = number // self.base.length
        self.indices = indices
    
    def __get_indices(self):
        return self.__indices
    
    def __set_indices(self, indices):
        new_indices = []
        for index in indices:
            assert index < self.base.length, ('Invalid index for base %r: %r'
                % (self.base, index))
            new_indices.append(index)
        self.__indices = new_indices
    
    def __get_values(self):
        return map(self.base.words.__getitem__, self.indices)
    
    def __set_values(self, values):
        self.__indices = map(self.base.words.index, values)
    
    base = property(__get_base, __set_base)
    decimal = property(__get_decimal, __set_decimal)
    indices = property(__get_indices, __set_indices)
    values = property(__get_values, __set_values)
 
 
DECIMAL = Base('0123456789', 'decimal')
 
BINARY = Base('01', 'binary')
BINARY.format = (
    lambda n: '0b' + ''.join(map(str, n.values)))
 
HEXADECIMAL = Base('0123456789ABCDEF', 'hexadecimal')
HEXADECIMAL.format = (
    lambda n: '0x' + ''.join(map(str, n.values)))
 
OCTAL = Base('01234567', 'octal')
OCTAL.format = (
    lambda n: '0o' + ''.join(map(str, n.values)))
 
ALPHA_LOWER = Base('abcdefghijklmnopqrstuvwxyz', 'alpha_lower')
ALPHA_UPPER = Base('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'alpha_upper')
ALPHA = Base('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 'alpha')