This is a traditional base converter with the twist that it accepts any strings as the digits for the input and output bases.
Besides all the normal base-converts, you can now create compact versions of huge numbers by converting them to a base that uses all the letters and numbers for its digits, for example.
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 | BASE2 = "01"
BASE10 = "0123456789"
BASE16 = "0123456789ABCDEF"
BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"
def baseconvert(number,fromdigits,todigits):
""" converts a "number" between two bases of arbitrary digits
The input number is assumed to be a string of digits from the
fromdigits string (which is in order of smallest to largest
digit). The return value is a string of elements from todigits
(ordered in the same way). The input and output bases are
determined from the lengths of the digit strings. Negative
signs are passed through.
decimal to binary
>>> baseconvert(555,BASE10,BASE2)
'1000101011'
binary to decimal
>>> baseconvert('1000101011',BASE2,BASE10)
'555'
integer interpreted as binary and converted to decimal (!)
>>> baseconvert(1000101011,BASE2,BASE10)
'555'
base10 to base4
>>> baseconvert(99,BASE10,"0123")
'1203'
base4 to base5 (with alphabetic digits)
>>> baseconvert(1203,"0123","abcde")
'dee'
base5, alpha digits back to base 10
>>> baseconvert('dee',"abcde",BASE10)
'99'
decimal to a base that uses A-Z0-9a-z for its digits
>>> baseconvert(257938572394L,BASE10,BASE62)
'E78Lxik'
..convert back
>>> baseconvert('E78Lxik',BASE62,BASE10)
'257938572394'
binary to a base with words for digits (the function cannot convert this back)
>>> baseconvert('1101',BASE2,('Zero','One'))
'OneOneZeroOne'
"""
if str(number)[0]=='-':
number = str(number)[1:]
neg=1
else:
neg=0
# make an integer out of the number
x=long(0)
for digit in str(number):
x = x*len(fromdigits) + fromdigits.index(digit)
# create the result in base 'len(todigits)'
res=""
while x>0:
digit = x % len(todigits)
res = todigits[digit] + res
x /= len(todigits)
if neg:
res = "-"+res
return res
|
Motivation and application
I needed a system to include a reference number in an outgoing email, so that a reply email could be tracked to the original context. I'm betting that words in the subject line are the most likely to be returned in a reply email (as opposed to words in the body or headers), so I sought a way to compress/obfuscate my reference number into a word that would comfortably fit in the subject line. Now instead of 20020111152908/20020129120001, I can simply include "H6Xwq/IjmAf". It's shorter, less prone to tampering, and it looks more like a magic cookie than some MTA junk. In fact, I could boost the security even more by privately shuffling the order in which I use the letters as digits (instead of A==0, B==1, etc).
Other uses
I didn't find a base converter in python upon doing some quick searches, so perhaps this code would be useful for everyday conversions as well.
Does not handle non-zero systems. This gives an incorrect answer for non-zero base systems. For instance, if BASE8=12345678 then decimal '9' should be octal '11'. Instead, it's given as '21'.
confusion about "non-zero systems" The digits for BASE8 would be "01234567", not "12345678". With the latter set of digits, decimal 9 is properly output as '22' (octal, but not with the standard digits). The standard octal for decimal '9' is '11'.
Note that baseconvert("9","123456789","12345678") will output '21', but that input is not a decimal 9. It's a decimal 8.
What abut OCT ? Python 2.3:
'11'
this is ok, but
than:
'13'
I thin, it should be 12 ??
Best regards.
Sorry. the BASE10 was wrong :)))
further confirmation. This problem appears to have something to do with the number of digits in the base10 number being converted.
In [28]: baseconvert(99,"01234567890","01234567") Out[28]: '154'
In [29]: baseconvert(100,"01234567890","01234567") Out[29]: '171'
0 (Zero) does not work? Been just trying baseconvert(0, BASE10, BASE62), it simply returns null string. A simple solution is to add:
just below the res="" line for the correct operation.
you can inter-convert with Word-representations. With a little re help, you can convert back from a word representation like "OneZeroOne". I believe this will work as long as you use words that start with a capital as you have done. The approach is to use an alternation regex expression to split the number into "digits" and then continue as you already do.
At the start of the def, put an "import re" statement and then replace the "for digit in str(number)" with the following:
Here is a demonstration:
I have posted the Py3K compatible code with LesPaul's suggested change to pastebin at http://pastebin.com/f54dd69d6