Welcome, guest | Sign In | My Account | Store | Cart

The function produces an arbitrary radix string representation of integer numbers.

Python, 57 lines
 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
# radix.py

"""
Defines str(number,radix) -- reverse function to int(str,radix) and long(str,radix)

number -- signed int or long,
radix  -- 2 to 36

Usage:
import radix
str_repr = radix.str( number, radix )

print radix.str( 10, 16 ), radix.str( 1570137287, 36 ) # a python

"""


import string


def str( number, radix ):
   """str( number, radix ) -- reverse function to int(str,radix) and long(str,radix)"""

   if not 2 <= radix <= 36:
      raise ValueError, "radix must be in 2..36"

   abc = string.digits + string.letters

   result = ''

   if number < 0:
      number = -number
      sign = '-'
   else:
      sign = ''

   while True:
      number, rdigit = divmod( number, radix )
      result = abc[rdigit] + result
      if number == 0:
         return sign + result

   # never here because number >= 0, radix > 0, we repeat (number /= radix)


if __name__ == '__main__':
   src = 'qwertyuioplkjhgfdsazxcvbnm0987654321'
   dst = 79495849566202193863718934176854772085778985434624775545L

   num = int( src, 36 )
   assert num == dst
   res = str( num, 36 )
   assert res == src
   print "%s radix 36 is\n%d decimal" % (src, dst)


# EOF

I've discovered that a function returning an arbitrary radix string from a number is missing in the language. So I implemented it to restore the symmetry.

Moon aka Sun

5 comments

Moon aka Sun (author) 18 years, 2 months ago  # | flag

--> Category: Algorithms. I'm sorry, it belongs rather to the Algorithms Category.

See also here: Numeric base converter that accepts arbitrary digits

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/111286

Raymond Hettinger 18 years, 2 months ago  # | flag

A few nits. Nicely written.

Here are a few nits to take it to industrial strength:

  • rename the function to base() or some such to avoid overwriting __builtin__.str()

  • only build abc once and do it outside the function

  • use ''.join() on a list instead of quadratic time string addition.

  • make divmod, abc, and result.append into locals for faster lookup in the loop.

    import string abc = string.digits + string.letters

    def base(number, radix): """base(number, radix) inverse function to int(str,radix) and long(str,radix) """

    if not 2 <= radix <= 36: raise ValueError, "radix must be in 2..36"

    result = [] addon = result.append if number < 0: number = -number addon('-') elif number == 0: addon('0')

    _divmod, _abc = divmod, abc while number: number, rdigit = _divmod(number, radix) addon(_abc[rdigit])

    result.reverse() return ''.join(result)

Richard Nichols III 14 years, 1 month ago  # | flag
added an optional minimim-width parameter.
note: '0' * -1 == ''

import string
abc = string.digits + string.letters

def base(number, radix, width=1):
   """base(number, radix)
         inverse function to int(str,radix) and long(str,radix)
   """

   if not 2 &lt;= radix &lt;= 36:
      raise ValueError, "radix must be in 2..36"

   result = []
   addon = result.append
   if number &lt;
      number = -number
      addon('-')

   _divmod, _abc = divmod, abc
   while number:
      number, rdigit = _divmod(number, radix)
      addon(_abc[rdigit])

   addon("0"*(width-len(result)))

   result.reverse()
   return ''.join(result)
Damon McCormick 13 years, 5 months ago  # | flag

Minus sign should be at the beginning. The code directly above puts the minus sign at the end instead of the beginning.

Here's the version I ended up with, which also allows you to use whatever characters you like as the digits:

def toRadixStr (number, radix, width=1,
          digits=string.digits+string.letters):
   """Inverse function to int(str,radix) and long(str,radix)."""
   digitCount = len(digits)
   if not 2 &lt;= radix &lt;= digitCount:
      raise ValueError, "radix must be in 2..%d" % digitCount
   result = []
   # convert some globals to locals for speed
   _divmod, _digits = divmod, digits
   append = result.append
   # check for a negative number
   if number &lt; 0:
       number = -number
       isNegative = True
   else:
       isNegative = False
   # append digits in reverse order
   while number:
      (number, remainder) = _divmod(number, radix)
      append(_digits[remainder])
   # append leading 0s
   leading0s = digits[0] * (width-len(result)) # note: "0" * -1 == ''
   append(leading0s)
   # append sign if necessary and reverse
   if isNegative:
      append('-')
   result.reverse()
   return ''.join(result)
Damon McCormick 13 years, 5 months ago  # | flag

typo. string.letters should be string.uppercase (or string.lowercase).

Created by Moon aka Sun on Tue, 16 Sep 2003 (PSF)
Python recipes (4591)
Moon aka Sun's recipes (1)

Required Modules

Other Information and Tasks