utils.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  27. base63_digits = "0123456789abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ-"
  28. decimal_char = "D"
  29. base62_char = "2"
  30. base63_char = "3"
  31. char_map = {
  32. decimal_char: decimal_digits,
  33. base62_char: base62_digits,
  34. base63_char: base63_digits,
  35. }
  36. def __init__(self, digits):
  37. self.digits = digits
  38. def __get_base_digits(self, value):
  39. if "-" in value:
  40. return self.base63_digits, self.base63_char
  41. elif self.letter_set.intersection(value):
  42. return self.base62_digits, self.base62_char
  43. else:
  44. return self.decimal_digits, self.decimal_char
  45. def encode(self, i):
  46. decimal_digits, b_char = self.__get_base_digits(i)
  47. results = self.convert(i, decimal_digits, self.digits)
  48. return "%s%s" % (b_char, results)
  49. def one_way_encode(self, i):
  50. """
  51. One way encode, not possible to decode. using base62 digits no -
  52. """
  53. return self.convert(i, self.base62_digits, self.digits)
  54. def decode(self, s):
  55. # strip out the first base_char.
  56. return self.convert(s[1 : len(s)], self.digits, self.char_map[s[0]])
  57. def convert(number, fromdigits, todigits):
  58. # Based on http://code.activestate.com/recipes/111286/
  59. if str(number)[0] == "-":
  60. number = str(number)[1:]
  61. neg = 1
  62. else:
  63. neg = 0
  64. # make an integer out of the number
  65. x = 0
  66. for digit in str(number):
  67. x = x * len(fromdigits) + fromdigits.index(digit)
  68. # create the result in base 'len(todigits)'
  69. if x == 0:
  70. res = todigits[0]
  71. else:
  72. res = ""
  73. while x > 0:
  74. digit = x % len(todigits)
  75. res = todigits[digit] + res
  76. x = int(x / len(todigits))
  77. if neg:
  78. res = "-" + res
  79. return res
  80. convert = staticmethod(convert)
  81. pbp_converter = BaseConverter(
  82. "012345abcdefghijklmnopqrstuvwxyz67" "ABCDEFGHIJKLMNOPQRSTUVWXYZ89"
  83. )
  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)