Rebaser in obfuscated Python

Here’s a fun piece of code. It does the same as the class Z rebaser, but while that one took 266 lines, this one does it in 25:

import sys as _S#def _toB10(N,B,S='-',n=0):#def _tostr(s):#_src=("from Orthall"
def _unpack(fn):# s,N=((1,N),(-1,N[1:]))[S==N[0]];p=len(N)-1# try:s=unicode(s)
 f,k,c,n={},0,chr(35),'\n'# for j in N:n+=_.index(j)*B**p;p-=1# except:s=str(s)
 with open(fn)as F:# return s*n or 0# return s#"elo"##def guess(N):#del _unpack
  for l in F:##### "returns possible base of N\nactual base of N may be larger"
   if c in l:#def _toBb(N,B,S='-',n=''):#J=("GXRZSzRW8:geFv=QUkGf'o@1>?b7v%J"
    i=0;q=l.split(c)[1:]# S,N=((n,N),((S,n)[B<0],-N))[B>0>N]#",wakm//q,yJgah*0"
    for S in q:# while N:N,i=N//B,N%B;N=(N,N+1)[i<0];n=_[(i,i-B)[i<0]]+n#"t&d6"
     s=str(k)+'_'+str(i);i+=1# return S+n or _[0]#"%")### return max(list(map(
     if n not in S:S+=n#from string import printable as _;_=_.swapcase()##"us")
     if f.get(s):f[s]+=S#def _ex(a):#def _tochr(h):#Q=('IYNK!1k4FaKTS(+fUT=byo'
     else:f[s]=S# for i in range(_S.maxunicode+1):# try:q=unichr(h)#'L3K*(TB-h'
   else:k+=1#  q=_tochr(i)# except:q=chr(h)#'SLhK,8KriA4kBYW>4X)r3w=8Nm3MQd')
 for i in sorted(f.keys()):exec(f[i],globals())#  if i>256:a+=q# return q
def rebase(N,B1,B2,sign='-'):#  elif q not in a:a+=q#_=_ex(_tostr(_))
 "converts a number N from base B1 to base B2"# return a####_.index,N)))+1
 N=_tostr(N)or _[0];o,m=N.count(sign),max(list(map(_.index,N)));a,b,c,d,e=_er()
 for i in[B1,B2]:#def _er():#_r=rebase;Y=_r(Q,83,96,'?');del Q;del _ex;del _S
  if _tostr(i)==i or i in e:raise ValueError(a)# n='Negative sign '
 if o>1:raise ValueError(b)# b=_tostr(n+'appears more than once')#__doc__=(
 if o and N[0]!=sign:raise ValueError(c)# a=_tostr("invalid base");c=(n+'is n'
 if m>=abs(B1)and m!=_.index(sign):#'ot leading the number');d=_tostr('unsuppo'
  raise TypeError(d.format(B1,_[m]))#'rted character for base {}: {}');e=[1,0,
 return _toBb(_toB10(N,B1,sign),B2,sign)#-1];return a,b,c,d,e#'\n'.join(
_unpack(_S.argv[0])##(Y,_r(J,88,95).format(len(_)),_src)));del _r;del J;del Y

There are nine functions in that. If you strip out any of the comments the code will fail to work. And despite the fact it works with Unicode and strings, this works both in Python 2.7 and 3.x (if you’re familiar with the pain of Unicode in Python 2, you’ll know why). This code is so great that here’s a picture of it so you can hang it on your wall.
 

You’ll have to save it to a file for it to work. You can open it up in an interpreter and start using it right way:

>>> rebase(8035495685003667352771426884227330043418238, 10, 95)
u'Numbers as text? naaah'
>>> guess(u"what bäse am I?")
229

Or you can import it and call help on it to see more about it:

>>> import sillyness
>>> help(sillyness)
Help on module sillyness:

NAME
    sillyness

FILE
    c:\sillyness.py

DESCRIPTION
    Rebaser module - converts a number from one base to another
    Valid bases are -65536 to 65536 (excluding 0, -1 and 1)
    from Orthallelous

FUNCTIONS
    guess(N)
        returns possible base of N
        actual base of N may be larger
    
    rebase(N, B1, B2, sign='-')
        converts a number N from base B1 to base B2

Note: you’ll have to change part of the last line from “_unpack(_S.argv[0])” to “_unpack(__file__)” to import it. Also it can only be imported once.
 
 
 
This all started when one day when I wondered if I could use all that extra space to the right of my code. Take for example this piece of code:

def Ten_to_1(n):
    'Converts a number in base 10 to base 1'
    if n<0:return''.join(['-','0'*abs(n)])
    elif n>0: return'0'*n
    else:return''

Look at all that empty space to the right of that! So inefficient with its space! So after some work and thought I developed the unpacker. It opens up a file, extracts out the comments, parses them and adds them to the global functions. Here’s an unobfuscated form:

def unpacker(filename):
    """multiple comment unpacker - unpacks multiple functions from the comments
    Note: To unpack multiple functions in the comments, there must be at least
     one line between them that does not have the comment character. This line
     with a lack of a comment denotes where a new function in the comments
     begins (this isn't necessarily true but it’s a good guideline to follow).
     The comment character, chr(35), must also not show up anywhere else
     in the file (as in a string). Can unpack multiple comments per line.
    """
    funcs, func_key, com, newL={}, 0, chr(35), '\n'

    with open(filename)as fn:
        for line in fn:
            if line.count(com):
                for i, sub_line in enumerate(line.split(com)[1:]):
                    sub_key=str(func_key)+'_'+str(i)
                    if not sub_line.count(newL):sub_line+=newL

                    if funcs.get(sub_key):funcs[sub_key]+=sub_line
                    else:funcs[sub_key]=sub_line
            else:func_key+=1

    for i in sorted(funcs.keys()):
        exec(funcs[i], globals())

The keys are numbered on where the comment started. They are sorted to insure the code is executed in the correct order.

In the 25 line rebaser above, I pass its own file name to the unpacker which then reads and adds the functions hidden in the comments. I limited the code to 80 characters long, but there’s no reason why it couldn’t be longer. There’s some loss of functionality from the class Z rebaser – it’s much slower and can’t handle as many bases, but I think that’s sufficient for 25 lines. It’ll cover either 131,069 bases or 2,228,221 bases, depending on your version of Python. It could go higher but you might run into errors. It can be avoided but there’s no guarantees:

>>> rebase('what',2228456,7)
u'3231106530212263106510044'

>>> rebase(163251635,7,2228456)

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    rebase(163251635,7,2228456)
  File "C:/Sillyness.py", line 24, in rebase
    return _toBb(_toB10(N,B1,sign),B2,sign)#-1];return a,b,c,d,e#'\n'.join(
  File "<string>", line 8, in _toBb
IndexError: string index out of range

If you’re interested in dissecting the code, I recommend first replacing the following line

 for i in sorted(f.keys()):exec(f[i],globals())#  if i>256:a+=q# return q

with this

 for i in sorted(f.keys()):print(i+'---\n'+f[i])#  if i>256:a+=q# return q

 
 

Merry Christmas!

Posted in Number Bases, Python

Leave a comment

In Archive
Design a site like this with WordPress.com
Get started