123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- """
- Convert numbers from base 10 integers to base X strings and back again.
- Original: http://www.djangosnippets.org/snippets/1431/
- Sample usage:
- >>> converter = the_converter
- >>> converter.encode('1234')
- 'DvY'
- >>> converter.decode('DvY')
- '1234'
- Tests:
- >>> converter.decode(converter.encode('1234')) == '1234'
- True
- >>> converter.decode(converter.encode('1234A')) == '1234A'
- True
- >>> converter.decode(converter.encode('1234A-')) == '1234A-'
- True
- >>> converter.decode(converter.encode('1234A-')) == '1234A'
- False
- """
- import time
- import string
- import datetime
- class BaseConverter(object):
- letter_set = set(string.letters)
- decimal_digits = "0123456789"
- base62_digits = "0123456789abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- base63_digits = "0123456789abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ-"
- decimal_char = "D"
- base62_char = "2"
- base63_char = "3"
- char_map = {
- decimal_char: decimal_digits,
- base62_char: base62_digits,
- base63_char: base63_digits,
- }
- def __init__(self, digits):
- self.digits = digits
- def __get_base_digits(self, value):
- if "-" in value:
- return self.base63_digits, self.base63_char
- elif self.letter_set.intersection(value):
- return self.base62_digits, self.base62_char
- else:
- return self.decimal_digits, self.decimal_char
- def encode(self, i):
- decimal_digits, b_char = self.__get_base_digits(i)
- results = self.convert(i, decimal_digits, self.digits)
- return "%s%s" % (b_char, results)
- def one_way_encode(self, i):
- """
- One way encode, not possible to decode. using base62 digits no -
- """
- return self.convert(i, self.base62_digits, self.digits)
- def decode(self, s):
- # strip out the first base_char.
- return self.convert(s[1 : len(s)], self.digits, self.char_map[s[0]])
- def convert(number, fromdigits, todigits):
- # Based on http://code.activestate.com/recipes/111286/
- if str(number)[0] == "-":
- number = str(number)[1:]
- neg = 1
- else:
- neg = 0
- # make an integer out of the number
- x = 0
- for digit in str(number):
- x = x * len(fromdigits) + fromdigits.index(digit)
- # create the result in base 'len(todigits)'
- if x == 0:
- res = todigits[0]
- else:
- res = ""
- while x > 0:
- digit = x % len(todigits)
- res = todigits[digit] + res
- x = int(x / len(todigits))
- if neg:
- res = "-" + res
- return res
- convert = staticmethod(convert)
- pbp_converter = BaseConverter(
- "012345abcdefghijklmnopqrstuvwxyz67" "ABCDEFGHIJKLMNOPQRSTUVWXYZ89"
- )
- def temp_code(now=None):
- """We need a unique temp code, so we get a timestamp to the
- microsecond and that should be good enough
- """
- if not now:
- now = datetime.datetime.now()
- return "%s%s" % (int(time.mktime(now.timetuple())), now.microsecond)
|