Scriviamo un minificatore


14

sfondo

I minifiers vengono utilizzati, comunemente, quando si offre JavaScript al tuo browser Web. È comunemente usato per ridurre il numero di byte che devono essere inviati. Il salvataggio della larghezza di banda è utile per ovvi motivi. Alcune persone usano gli offuscatori (che intenzionalmente rendono il codice più difficile da leggere), non sto parlando di quelli.

Minificheremo Python 2

Stavo discutendo se usare o meno JavaScript o Python per l'esperienza di minimizzazione e ho deciso su Python per due motivi: lo spazio bianco è importante e penso che aggiungerà un'interessante dinamica al problema. Inoltre, l'utilizzo di Python 2.7 fornirà un'altra dinamica, come rimuovere il superfluo ()durante una stampa (cioè print("Hello world")vs. print"Hello world"). Personalmente avrei preferito aprirlo a qualsiasi lingua, ma per alcune lingue questo processo non avrebbe molto senso. E quale lingua decidi di minimizzare avrà un impatto diretto sul tuo punteggio (e se anche la lingua può essere minimizzata).

Specifiche

Il tuo obiettivo è modificare il codice solo in un modo che non cambierà comunque la sua funzionalità. È possibile, ovviamente, modificare i nomi delle variabili (all'interno del programma di minimizzazione) purché non influisca sull'output (tenere traccia dell'ambito ). Anche se ti sto dando un programma specifico, ti preghiamo di non ottimizzare il caso di test in quanto tutte le scappatoie standard sono vietate.

Punteggio : durata del programma dopo averlo minimizzato.

Input : qualsiasi programma Python 2.7 (che non contiene errori)

Output : una versione minimizzata.

Sebbene il tuo codice dovrebbe essere in grado di accogliere tutti gli input validi di Python 2.7, è necessario testare il tuo script rispetto a qualcosa per dimostrarne l'efficacia.

Fare clic qui per visualizzare il programma di esempio.

Rendere il problema più accessibile

Sentiti libero di usare o modificare qualsiasi codice trovato all'interno della mia soluzione (elencato di seguito). Ho fatto questo per iniziare con la gestione delle quotazioni di base del preventivo; tuttavia, è possibile espanderlo al rientro e così via

Esempi di modi per minimizzare Python

Tutto lo spazio bianco potrebbe essere sostituito con la quantità minima possibile (riconosco che in Python puoi fare alcune cose complicate con le schede , ma lo lascerò a te decidere se implementarlo o meno).

Esempio

Il seguente:

def print_a_range(a):
    for i in range(a):
        print(i)

Potrebbe essere:

def print_a_range(a):
 for i in range(a):
  print(i)

Tecnicamente, se c'è solo una riga all'interno di un loop, puoi comprimerlo ancora di più:

def print_a_range(a):
 for i in range(a):print(i)  #Note, you can also remove the `()` here.

Tuttavia, esiste un altro modo per minimizzare gli spazi bianchi in Python:

Il seguente:

print ([a * 2 for a in range(20) if a % 2 == 0])

Potrebbe essere:

print([a*2for a in range(20)if a%2==0])

Si noti che non è necessario uno spazio tra 2e for. Variabile, funzioni e parole chiave non possono iniziare con un numero. Quindi, l'interprete Python va bene <num><keyword>, senza spazio. Si dovrebbe anche notare che non è necessario uno spazio tra )e if.

Nota, non è necessario modificare l'output del programma! Così:

print"f(x)=x*2 is a great equation!"

L'istruzione di stampa sopra dovrebbe rimanere la stessa perché rimuovendo lo spazio tra 2e ismodificare l'output.



Sidenote: non esiste un programma in grado di produrre l' equivalente più breve di qualsiasi programma di input arbitrario, in questa discussione
Leaky Nun,

Ci fatevi alcuni strumenti pitone Minifier già . Non credo che questa domanda possa ricevere una soluzione migliore rispetto agli strumenti già usciti.
TSH

Sta cambiando '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'in '1'*100permesso? È necessario fare poiché il comportamento è lo stesso?
l4m2

Risposte:


2

Punteggio Python 2.7, 2013

Questo programma può essere utilizzato come riferimento e ti è consentito prendere il codice seguente, modificarlo e quindi pubblicarlo nelle tue soluzioni.

Con il senno di poi, forse avrei dovuto usare regex anche per la gestione delle quotazioni, ma penso che nel suo stato attuale potrebbe essere sufficiente per far ripartire le persone nel problema.

Perché ho scelto Python 2.7: ho pensato che sarebbe stato più facile testare per vedere se ho fatto il crash del programma tramite la execparola chiave.

Questo codice introduce il programma come in.txt.

Ho pensato che avrei dovuto almeno far rotolare la palla per chiunque volesse partecipare scrivendo un parser di citazione (che succede anche per gestire i commenti) e un breve esempio su come regex, quando combinato con il parser di quotazione, può davvero cambiare il gioco in termini di complessità di questo problema.

Nota: c'è ancora molto spazio per migliorare questo minificatore. Come se potessi giocare con il rientro, i nomi delle variabili e la rimozione delle parentesi quando vengono utilizzate le mie parole chiave, come printo yield.

import re

with open("in.txt","r") as fi:
    code = fi.read()

class QuoteHandler():
    def __init__(self):
        pass
    def loadCode(self,code):
        quoteFlag = False
        currentQuoteChar = ""
        ignoreNext = False
        inEndLineComment=False
        startLocation = 0

        self.reAddStrings = []

        outStr = ""

        for i, character in enumerate(code):
            if ignoreNext:
                ignoreNext = False
            elif inEndLineComment:
                if character in "\r\n":
                    inEndLineComment=False
            elif character == "#" and not quoteFlag:
                inEndLineComment = True
            elif character in "'\"" and (currentQuoteChar == character or not quoteFlag):
                if quoteFlag:
                    self.reAddStrings.append(code[startLocation+1:i])
                else:
                    currentQuoteChar = character
                    startLocation = i
                quoteFlag = not quoteFlag
            elif character == "\\":
                ignoreNext = True

            if not inEndLineComment and not quoteFlag:
                outStr+=character                
        return outStr

    def find_all_locations(self,substr,code):
        return [m.start() for m in re.finditer(substr, code)]

    def unloadCode(self,code):
        temp = self.reAddStrings[::-1]
        for i, location in enumerate(list(self.find_all_locations('"',code))[::-1]):
            code = code[:location] + "\"" + temp[i] + code[location:]
        return code

def applyRegexes(code):#\w here?
    operatorRegexCleaner = ["([\d\/*\-\"=,'+{}:[\](\)])","[ \t]+","(\w)"]
    regexes = [
        [''.join(operatorRegexCleaner),r"\1\2"],
        [''.join(operatorRegexCleaner[::-1]),r"\1\2"],#removes whitespace between operators
        ["\n\s*\n","\n"]#removes empty lines
    ]
    for regex in regexes:
        code = re.sub(regex[0],regex[1],code)
    return code

qh = QuoteHandler()
code = qh.loadCode(code)
code = applyRegexes(code)
code = qh.unloadCode(code)
print(code)
exec(code)

Uscita del programma:

def factor(factor_number):
    for n in range(2,factor_number):
        if factor_number % n==0:    
            yield(n)
def gcd(a,b):
    """Calculate the Greatest Common Divisor of a and b.

    Unless b==0, the result will have the same sign as b (so that when
    b is divided by it, the result comes out positive).
    """
    while b:
         a,b=b,a%b 
    return a
class Apricot:
    def __init__(self):
        self.mold=False
    def get(self):
        return self.mold
    def update(self):
        self.mold=not self.mold
    def blue(self):return5
def tell_me_about_these_numbers(*a):
    print("%d is the first number!" % a[0])
    print("{} / 3 is {}".format(a[0],a[0]/3.))
    myFavorate=Apricot()
    for number in a:
        print list(factor(number))
        myFavorate.update()
    print[gcd(a,b)for a,b in zip(a[:-1],a[1:])]
    print(myFavorate.get())
tell_me_about_these_numbers(5,6,9,45,200)
print"Let's play with scope!"
a,b=10,9
def randomFunction(a):
    print(a)
randomFunction(b)
print(a)
for a in range(100):
    b+=a
print(a)
print(b)
li=[]
for i in range(10):
 li.append(i*2)
print(li)
print([i*2for i in range(10)])
a=c=b=d=e=f=g=h=i=j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z=5
print(a)
a-=1
print(a)
g=10
print(str(10**g+5)[::-1])
def blue_fish(a):
    def blue_fish(a):
        def blue_fish(a):
            return a
        a+=1
        return blue_fish(a)
    a-=1
    return blue_fish(a)
print(blue_fish(10))
def blue_fish(a):
    if a==0:
        return"0"
    return"1" +blue_fish(a-1)
print(blue_fish(5))
blue_fish=lambda a,b,c:a*b*c
print(blue_fish(1,2,3))
blue_fish=lambda*a:reduce(lambda a,b:a*b,a)
print(blue_fish(1,2,3))
print(max([[6,1],[5,2],[4,3],[3,4],[2,5],[1,6]],key=lambda a:a[1]))
print(zip(*[[1],[2],[3],[4],[5]]))
print"Now let's test to see if you handle quotes correctly:"
print"test \'many diffent\' \"types of \" quotes, even with \' \" trailing quotes"
print"""

Multi line quotes are great too!

"""
a=""" ::
one more multi-line quote won't hurt
"""
print a
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.