Advertisement
AlanReiAkemi

bases.py

Jan 16th, 2016
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.12 KB | None | 0 0
  1. # bases.py
  2. # python port for https://github.com/aseemk/bases.js
  3. # Utility for converting numbers to/from different bases/alphabets.
  4. # See README.md for details.
  5.  
  6. import math
  7. import re
  8. import string
  9.  
  10. class Bases(object):
  11.  
  12.     # init
  13.     def __init__(self):
  14.  
  15.         # Known alphabets:
  16.         self.numerals = string.digits
  17.         self.lettersLowercase = string.ascii_lowercase
  18.         self.lettersUppercase = string.ascii_uppercase
  19.         self.knownAlphabets = {}
  20.  
  21.         # Each of the number ones, starting from base-2 (base-1 doesn't make sense?):
  22.         i = 2
  23.         while i <= 10:
  24.             self.knownAlphabets[i] = self.numerals[:i]
  25.             i += 1
  26.  
  27.         # python's native hex is 0-9 followed by *lowercase* a-f, so we'll take that
  28.         # approach for everything from base-11 to base-16:
  29.         i = 11
  30.         while i <= 16:
  31.             self.knownAlphabets[i] = self.numerals + self.lettersLowercase[:i - 10]
  32.             i += 1
  33.  
  34.         # We also model base-36 off of that, just using the full letter alphabet:
  35.         self.knownAlphabets[36] = self.numerals + self.lettersLowercase
  36.  
  37.         # And base-62 will be the uppercase letters added:
  38.         self.knownAlphabets[62] = self.numerals + self.lettersLowercase + self.lettersUppercase
  39.  
  40.         # For base-26, we'll assume the user wants just the letter alphabet:
  41.         self.knownAlphabets[26] = self.lettersLowercase
  42.  
  43.         # We'll also add a similar base-52, just letters, lowercase then uppercase:
  44.         self.knownAlphabets[52] = self.lettersLowercase + self.lettersUppercase
  45.  
  46.         # Base-64 is a formally-specified alphabet that has a particular order:
  47.         # http://en.wikipedia.org/wiki/Base64 (and Python follows this too)
  48.         # TODO FIXME But our code above doesn't add padding! Don't use this yet...
  49.         self.knownAlphabets[64] = self.lettersUppercase + self.lettersLowercase + self.numerals + '+/'
  50.  
  51.         # Flickr and others also have a base-58 that removes confusing characters, but
  52.         # there isn't consensus on the order of lowercase vs. uppercase... =/
  53.         # http://www.flickr.com/groups/api/discuss/72157616713786392/
  54.         # https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart
  55.         # https://github.com/dougal/base58/blob/master/lib/base58.rb
  56.         # http://icoloma.blogspot.com/2010/03/create-your-own-bitly-using-base58.html
  57.         # We'll arbitrarily stay consistent with the above and using lowercase first:
  58.         self.knownAlphabets[58] = re.sub(r'[0OlI]', '', self.knownAlphabets[62])
  59.  
  60.         # And Douglas Crockford shared a similar base-32 from base-36:
  61.         # http://www.crockford.com/wrmg/base32.html
  62.         # Unlike our base-36, he explicitly specifies uppercase letters
  63.         self.knownAlphabets[32] = self.numerals + re.sub(r'[ILOU]', '', self.lettersUppercase)
  64.  
  65.         # Do this for all known alphabets:
  66.         for base in self.knownAlphabets:
  67.             if base in self.knownAlphabets:
  68.                 self.makeAlias(base, self.knownAlphabets[base])
  69.  
  70.     # Returns a stringing representation of the given number for the given alphabet:
  71.     def toAlphabet(self, num, alphabet):
  72.         base = len(alphabet)
  73.      
  74.         digits = []# these will be in reverse order since arrays are stacks
  75.         # execute at least once, even if num is 0, since we should return the '0':
  76.         while num >= 0:
  77.             digits.append(num % base)# TODO handle negatives properly?
  78.             num = math.floor(num / base)
  79.             if num == 0:
  80.                 break
  81.         chars = [];
  82.         while len(digits):
  83.             chars.append(alphabet[int(digits.pop())])
  84.         return ''.join(chars)
  85.  
  86.     # Returns an integer representation of the given stringing for the given alphabet:
  87.     def fromAlphabet(self, strRep, alphabet):
  88.         base = len(alphabet)
  89.         pos = 0
  90.         num = 0
  91.         c = False
  92.         while len(strRep):
  93.             c = strRep[len(strRep) - 1]
  94.             strRep = strRep[:len(strRep) - 1]
  95.             num += math.pow(base, pos) * alphabet.index(c)
  96.             pos += 1
  97.         return int(num)
  98.  
  99.     # And a generic alias too:
  100.     def toBase(self, num, base):
  101.         return self.toAlphabet(num, self.knownAlphabets[base])
  102.  
  103.     def fromBase(self, strRep, base):
  104.         return self.fromAlphabet(strRep, self.knownAlphabets[base])
  105.  
  106.     # Closure helper for convenience aliases like bases.toBase36():
  107.     def makeAlias(self, base, alphabet):
  108.         setattr(self, 'toBase' + str(base), lambda num: self.toAlphabet(num, alphabet))
  109.         setattr(self, 'fromBase' + str(base), lambda strRep: self.fromAlphabet(strRep, alphabet))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement