Gustavo Picon is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

tabo / numconv

Python library to convert strings to numbers and numbers to strings. Docs: http://docs.tabo.pe/numconv/tip/

Clone this repository (size: 168.1 KB): HTTPS / SSH
hg clone https://bitbucket.org/tabo/numconv
hg clone ssh://hg@bitbucket.org/tabo/numconv

numconv / numconv.py

commit
c4e7f8a9fba1
parent
1f64ca152ceb
branch
default
tags
1.1

updated the documentation Makefile to have a flexible html output location

1
a035ba7fb21b
# -*- coding: utf-8 -*-
2
0d8c44c9fa40
"""
3
a035ba7fb21b
4
0d8c44c9fa40
numconv
5
0d8c44c9fa40
-------
6
0d8c44c9fa40
7
0d8c44c9fa40
:synopsys: Python library to convert strings to numbers and numbers to
8
0d8c44c9fa40
           strings.
9
0d8c44c9fa40
:copyright: 2008 by Gustavo Picon
10
0d8c44c9fa40
:license: Apache License 2.0
11
0d8c44c9fa40
:version: 1.1
12
0d8c44c9fa40
:url: http://code.google.com/p/numconv/
13
0d8c44c9fa40
:documentation:
14
0d8c44c9fa40
   `numconv-docs
15
0d8c44c9fa40
   <http://code.google.com/p/numconv/source/browse/trunk/docs/html/index.html>`_
16
0d8c44c9fa40
:examples:
17
0d8c44c9fa40
   `numconv-tests
18
1f64ca152ceb
   <http://numconv.googlecode.com/svn/docs/index.html>`_
19
0d8c44c9fa40
20
0d8c44c9fa40
21
0d8c44c9fa40
:mod:`numconv` converts a string into a number and a number into a string using
22
0d8c44c9fa40
default or user supplied encoding alphabets.
23
0d8c44c9fa40
24
0d8c44c9fa40
constants
25
0d8c44c9fa40
~~~~~~~~~
26
0d8c44c9fa40
27
0d8c44c9fa40
.. data:: BASE85
28
0d8c44c9fa40
29
0d8c44c9fa40
   Alphabet defined in section 4 of :rfc:`1924`. Supposed to be a joke (it is
30
0d8c44c9fa40
   an April's fools RFC after all), but is quite useful because can be used as
31
0d8c44c9fa40
   a base for the most common numeric conversions.
32
0d8c44c9fa40
33
0d8c44c9fa40
.. data:: BASE16
34
0d8c44c9fa40
          BASE32
35
0d8c44c9fa40
          BASE32HEX
36
0d8c44c9fa40
          BASE64
37
0d8c44c9fa40
          BASE64URL
38
0d8c44c9fa40
39
0d8c44c9fa40
   Alphabets defined in :rfc:`4648`. Not really for common numeric conversion
40
0d8c44c9fa40
   use.
41
a035ba7fb21b
42
a035ba7fb21b
"""
43
a035ba7fb21b
44
0d8c44c9fa40
VERSION = (1, 1)
45
a035ba7fb21b
46
a035ba7fb21b
# from april fool's rfc 1924
47
a035ba7fb21b
BASE85 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' \
48
a035ba7fb21b
         '!#$%&()*+-;<=>?@^_`{|}~'
49
a035ba7fb21b
50
a035ba7fb21b
# rfc4648 alphabets
51
a035ba7fb21b
BASE16 = BASE85[:16]
52
a035ba7fb21b
BASE32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
53
a035ba7fb21b
BASE32HEX = BASE85[:32]
54
a035ba7fb21b
BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
55
a035ba7fb21b
BASE64URL = BASE64[:62] + '-_'
56
a035ba7fb21b
57
a035ba7fb21b
# cached maps
58
a035ba7fb21b
CMAPS = {}
59
a035ba7fb21b
60
a035ba7fb21b
61
a035ba7fb21b
def int2str(num, radix=10, alphabet=BASE85):
62
0d8c44c9fa40
    """Converts an integer into a string.
63
0d8c44c9fa40
64
0d8c44c9fa40
    :param num: A numeric value to be converted to another base as a string.
65
0d8c44c9fa40
    :param radix: The base that will be used in the conversion.
66
0d8c44c9fa40
       The default value is 10 for decimal conversion.
67
0d8c44c9fa40
    :param alphabet: A string that will be used as a encoding alphabet.
68
0d8c44c9fa40
69
0d8c44c9fa40
       The length of the alphabet can be longer than the radix. In this case
70
0d8c44c9fa40
       the alphabet will be internally truncated.
71
0d8c44c9fa40
72
0d8c44c9fa40
       The default value is :data:`numconv.BASE85`
73
0d8c44c9fa40
74
0d8c44c9fa40
    :rtype: string
75
0d8c44c9fa40
76
0d8c44c9fa40
    :raise TypeError: when *num* isn't an integer
77
0d8c44c9fa40
    :raise ValueError: when *num* isn't positive
78
0d8c44c9fa40
    :raise TypeError: when *radix* isn't an integer
79
0d8c44c9fa40
    :raise ValueError: when *radix* is invalid
80
0d8c44c9fa40
    :raise ValueError: when *alphabet* has duplicated characters
81
0d8c44c9fa40
82
0d8c44c9fa40
    **Examples** (taken from :file:`tests.py`):
83
0d8c44c9fa40
       
84
0d8c44c9fa40
       3735928559 to hexadecimal::
85
0d8c44c9fa40
86
0d8c44c9fa40
           >> numconv.int2str(3735928559, 16)
87
0d8c44c9fa40
           'DEADBEEF'
88
0d8c44c9fa40
89
0d8c44c9fa40
       10284 to binary::
90
0d8c44c9fa40
91
0d8c44c9fa40
           >> numconv.int2str(19284, 2)
92
0d8c44c9fa40
           '100101101010100'
93
0d8c44c9fa40
94
0d8c44c9fa40
       37 to base 4 using a custom dictionary::
95
0d8c44c9fa40
96
0d8c44c9fa40
           >> numconv.int2str(37, 4, 'rofl')
97
0d8c44c9fa40
           'foo'
98
0d8c44c9fa40
99
0d8c44c9fa40
       Very large number to :data:`~numconv.BASE85`::
100
0d8c44c9fa40
101
0d8c44c9fa40
           >> numconv.int2str(2693233728041137L, 85)
102
0d8c44c9fa40
           '~123AFz@'
103
0d8c44c9fa40
104
0d8c44c9fa40
    """
105
a035ba7fb21b
    if alphabet not in CMAPS:
106
a035ba7fb21b
        # just to validate the alphabet
107
a035ba7fb21b
        getcmap(alphabet)
108
a035ba7fb21b
    if int(num) != num:
109
a035ba7fb21b
        raise TypeError, 'number must be an integer'
110
a035ba7fb21b
    if num < 0:
111
a035ba7fb21b
        raise ValueError, 'number must be positive'
112
a035ba7fb21b
    if int(radix) != radix:
113
a035ba7fb21b
        raise TypeError, 'radix must be an integer'
114
a035ba7fb21b
    if not 2 <= radix <= len(alphabet):
115
a035ba7fb21b
        raise ValueError, 'radix must be >= 2 and <= %d' % (len(alphabet),)
116
a035ba7fb21b
    ret = ''
117
a035ba7fb21b
    while True:
118
a035ba7fb21b
        ret = alphabet[num % radix] + ret
119
a035ba7fb21b
        if num < radix:
120
a035ba7fb21b
            break
121
a035ba7fb21b
        num //= radix
122
a035ba7fb21b
    return ret
123
a035ba7fb21b
124
0d8c44c9fa40
125
a035ba7fb21b
def str2int(num, radix=10, alphabet=BASE85):
126
0d8c44c9fa40
    """Converts a string into an integer.
127
0d8c44c9fa40
128
0d8c44c9fa40
    If possible, the built-in python conversion will be used for speed
129
0d8c44c9fa40
    porpuses.
130
0d8c44c9fa40
131
0d8c44c9fa40
    :param num: A string that will be converted to an integer.
132
0d8c44c9fa40
    :param radix: The base that will be used in the conversion.
133
0d8c44c9fa40
       The default value is 10 for decimal conversion.
134
0d8c44c9fa40
    :param alphabet: A string that will be used as a encoding alphabet.
135
0d8c44c9fa40
136
0d8c44c9fa40
       The length of the alphabet can be longer than the radix. In this case
137
0d8c44c9fa40
       the alphabet will be internally truncated.
138
0d8c44c9fa40
139
0d8c44c9fa40
       The default value is :data:`numconv.BASE85`
140
0d8c44c9fa40
141
0d8c44c9fa40
    :rtype: integer
142
0d8c44c9fa40
143
0d8c44c9fa40
    :raise TypeError: when *radix* isn't an integer
144
0d8c44c9fa40
    :raise ValueError: when *radix* is invalid
145
0d8c44c9fa40
    :raise ValueError: when *num* is invalid
146
0d8c44c9fa40
    :raise ValueError: when *alphabet* has duplicated characters
147
0d8c44c9fa40
148
0d8c44c9fa40
    **Examples** (taken from :file:`tests.py`):
149
0d8c44c9fa40
       
150
0d8c44c9fa40
       Hexadecimal 'DEADBEEF' to integer::
151
0d8c44c9fa40
152
0d8c44c9fa40
          >> numconv.str2int('DEADBEEF', 16)
153
0d8c44c9fa40
          3735928559L
154
0d8c44c9fa40
155
0d8c44c9fa40
       Binary '100101101010100' to integer::
156
0d8c44c9fa40
157
0d8c44c9fa40
           >> numconv.str2int('100101101010100', 2)
158
0d8c44c9fa40
           19284
159
0d8c44c9fa40
160
0d8c44c9fa40
       Base 4 with custom encoding 'foo' to integer::
161
0d8c44c9fa40
162
0d8c44c9fa40
           >> numconv.str2int('foo', 4, 'rofl')
163
0d8c44c9fa40
           37
164
0d8c44c9fa40
165
0d8c44c9fa40
       :data:`~numconv.BASE85` '~123AFz@' to integer::
166
0d8c44c9fa40
167
0d8c44c9fa40
           >> numconv.str2int('~123AFz@', 85)
168
0d8c44c9fa40
           2693233728041137L
169
0d8c44c9fa40
170
0d8c44c9fa40
    """
171
a035ba7fb21b
    if alphabet not in CMAPS:
172
a035ba7fb21b
        getcmap(alphabet)
173
a035ba7fb21b
    if int(radix) != radix:
174
a035ba7fb21b
        raise TypeError, 'radix must be an integer'
175
a035ba7fb21b
    if not 2 <= radix <= len(alphabet):
176
a035ba7fb21b
        raise ValueError, 'radix must be >= 2 and <= %d' % (len(alphabet),)
177
a035ba7fb21b
    if radix <= 36 and alphabet[:radix].lower() == BASE85[:radix].lower():
178
a035ba7fb21b
        return int(num, radix)
179
a035ba7fb21b
    ret = 0
180
a035ba7fb21b
    lmap = CMAPS[alphabet]
181
a035ba7fb21b
    lalphabet = alphabet[:radix]
182
a035ba7fb21b
    for char in num:
183
a035ba7fb21b
        if char not in lalphabet:
184
a035ba7fb21b
            raise ValueError, "invalid literal for radix2int() " \
185
a035ba7fb21b
                "with radix %d: '%s'" % (radix, num)
186
a035ba7fb21b
        ret = ret * radix + lmap[char]
187
a035ba7fb21b
    return ret
188
a035ba7fb21b
189
0d8c44c9fa40
190
a035ba7fb21b
def getcmap(alphabet):
191
a035ba7fb21b
    """Builds an internal alphabet lookup table, to be stored in CMAPS"""
192
a035ba7fb21b
    ret = dict(zip(alphabet, range(len(alphabet))))
193
a035ba7fb21b
    if len(ret) != len(alphabet):
194
a035ba7fb21b
        raise ValueError, "duplicate characters found in '%s'" % (alphabet,)
195
a035ba7fb21b
    CMAPS[alphabet] = ret
196
a035ba7fb21b
    return ret
197
a035ba7fb21b