# Python 2.7, 794 <!-- language-all: lang-python --> I have been meaning to build a minifier for Python for a while, so this is a good opportunity to investigate the problem. The program uses a mix of regular expression analysis, and Python parser operations. White space is minimised. Variable that are defined by the user are replaced by a single letter variable (which is not in use!). Finally the `while True` statement is put on a diet. The three test cases all verify as running correctly. I could imagine some pathological examples which could result in errors in the generated code but the algorithm should be robust under most circumstances. ## Results 228 t1.py 128 t2.py 438 t3.py 794 total ## Code import sys import re from tokenize import generate_tokens from token import tok_name from keyword import iskeyword wr = sys.stdout.write def pyparse(text): 'Return [TYPE,TOKEN] pair list' # Use KEYWORD,NAME,NUMBER,OP,STRING,NL,NEWLINE,COMMENT,INDENT,DEDENT rawtokens = generate_tokens(text.readline) tokens = [[tok_name[n], t] for n,t,p1,p2,dx in rawtokens] for tpair in tokens: if tpair[0] == 'NAME' and iskeyword(tpair[1]): tpair[0] = 'KEYWORD' return tokens def finduservars(filename): 'Return a set of user variables that we can replace with a-zA-Z' varset = set() for line in open(filename): line = line.strip() match = re.match(r'def\s+(\w+)\s*\((.*)\)\s*:', line) if match: func, args = match.groups() varset.add(func) arglist = re.findall(r'(\w+|=)', args) for a in arglist: if a == '=': break # keyword args follow - too hard to parse varset.add(a) continue match = re.match(r'(\w+)\s*=.+', line) if match: assigned = match.group(1) varset.add(assigned) continue return set(v for v in list(varset) if len(v) > 1) filename = sys.argv[1] tokenlist = pyparse(open(filename)) # Build map for var->char conversion: varset = finduservars(filename) singles = [text for tok,text in tokenlist if tok=='NAME' and len(text)==1] allvar = [chr(n) for n in range(97,123)+range(65,91)] charvar = [c for c in allvar if c not in singles] varreplaced = list(varset)[:len(charvar)] varmap = dict((v, charvar.pop(0)) for v in varreplaced) prev = 'NONE' indent = [''] output = [] add = output.append for tok, text in tokenlist: if tok == 'NL': continue elif tok == 'INDENT': indent.append( text.replace(' ', ' ') ) output[-1] = indent[-1] elif tok == 'DEDENT': indent.pop(-1) output[-1] = indent[-1] elif tok == 'NEWLINE': add(text) add(indent[-1]) elif tok in 'KEYWORD,NAME,NUMBER': if prev in 'KEYWORD,NAME,NUMBER': add(' ') if tok == 'NAME': if output[-2] == 'while' and text == 'True': add('1') # common verbose idiom else: add(varmap.get(text, text)) else: add(text) else: add(text) prev = tok wr(''.join(output))