utils.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. """
  2. Convert numbers from base 10 integers to base X strings and back again.
  3. Original: http://www.djangosnippets.org/snippets/1431/
  4. Sample usage:
  5. >>> converter = the_converter
  6. >>> converter.encode('1234')
  7. 'DvY'
  8. >>> converter.decode('DvY')
  9. '1234'
  10. Tests:
  11. >>> converter.decode(converter.encode('1234')) == '1234'
  12. True
  13. >>> converter.decode(converter.encode('1234A')) == '1234A'
  14. True
  15. >>> converter.decode(converter.encode('1234A-')) == '1234A-'
  16. True
  17. >>> converter.decode(converter.encode('1234A-')) == '1234A'
  18. False
  19. """
  20. import time
  21. import string
  22. import datetime
  23. class BaseConverter(object):
  24. letter_set = set(string.letters)
  25. decimal_digits = "0123456789"
  26. base62_digits = "0123456789abcdefghijklmnopqrstuvwxyz" \
  27. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  28. base63_digits = "0123456789abcdefghijklmnopqrstuvwxyz" \
  29. "ABCDEFGHIJKLMNOPQRSTUVWXYZ-"
  30. decimal_char = "D"
  31. base62_char = "2"
  32. base63_char = "3"
  33. char_map = {
  34. decimal_char: decimal_digits,
  35. base62_char: base62_digits,
  36. base63_char: base63_digits}
  37. def __init__(self, digits):
  38. self.digits = digits
  39. def __get_base_digits(self, value):
  40. if '-' in value:
  41. return self.base63_digits, self.base63_char
  42. elif self.letter_set.intersection(value):
  43. return self.base62_digits, self.base62_char
  44. else:
  45. return self.decimal_digits, self.decimal_char
  46. def encode(self, i):
  47. decimal_digits, b_char = self.__get_base_digits(i)
  48. results = self.convert(i, decimal_digits, self.digits)
  49. return "%s%s" % (b_char, results)
  50. def one_way_encode(self, i):
  51. """
  52. One way encode, not possible to decode. using base62 digits no -
  53. """
  54. return self.convert(i, self.base62_digits, self.digits)
  55. def decode(self, s):
  56. # strip out the first base_char.
  57. return self.convert(s[1: len(s)], self.digits, self.char_map[s[0]])
  58. def convert(number, fromdigits, todigits):
  59. # Based on http://code.activestate.com/recipes/111286/
  60. if str(number)[0] == '-':
  61. number = str(number)[1:]
  62. neg = 1
  63. else:
  64. neg = 0
  65. # make an integer out of the number
  66. x = 0
  67. for digit in str(number):
  68. x = x * len(fromdigits) + fromdigits.index(digit)
  69. # create the result in base 'len(todigits)'
  70. if x == 0:
  71. res = todigits[0]
  72. else:
  73. res = ""
  74. while x > 0:
  75. digit = x % len(todigits)
  76. res = todigits[digit] + res
  77. x = int(x / len(todigits))
  78. if neg:
  79. res = '-' + res
  80. return res
  81. convert = staticmethod(convert)
  82. pbp_converter = BaseConverter('012345abcdefghijklmnopqrstuvwxyz67'
  83. 'ABCDEFGHIJKLMNOPQRSTUVWXYZ89')
  84. def temp_code(now=None):
  85. """We need a unique temp code, so we get a timestamp to the
  86. microsecond and that should be good enough
  87. """
  88. if not now:
  89. now = datetime.datetime.now()
  90. return "%s%s" % (int(time.mktime(now.timetuple())), now.microsecond)