Mari kita menulis Minifier

14

Latar Belakang

Minifier digunakan, biasanya, saat menyajikan JavaScript ke Browser Web Anda. Ini biasanya digunakan untuk mengurangi jumlah byte yang harus dikirim. Menghemat bandwidth berguna untuk alasan yang jelas. Beberapa orang menggunakan obfuscaters (yang sengaja membuat kode lebih sulit dibaca), saya tidak membicarakannya.

Kami akan memperkecil Python 2

Saya berdebat tentang apakah menggunakan JavaScript atau Python untuk pengalaman minifying atau tidak, dan saya memutuskan pada Python karena dua alasan: ruang putih penting dan saya pikir itu akan menambah dinamika masalah yang menarik. Selain itu, menggunakan Python 2.7 akan memberikan dinamika lain, seperti menghapus berlebihan ()saat mencetak (yaitu print("Hello world")vs. print"Hello world"). Secara pribadi, saya lebih suka membukanya untuk bahasa apa pun, tetapi untuk beberapa bahasa proses ini tidak masuk akal. Dan, bahasa apa yang Anda putuskan untuk dikurangi akan berdampak langsung pada skor Anda (dan jika bahasa itu bahkan dapat diperkecil).

Spesifikasi

Tujuan Anda adalah hanya memodifikasi kode dengan cara yang tidak akan mengubah fungsinya dengan cara apa pun. Anda dapat, tentu saja, mengubah nama variabel (di dalam program minifying Anda) selama itu tidak mempengaruhi output (melacak cakupan ). Meskipun saya memberi Anda program khusus, tolong jangan optimalkan untuk kasus uji karena semua lubang standar dilarang.

Nilai : panjang program setelah Anda memperkecilnya.

Input : Setiap program Python 2.7 (yang tidak mengandung kesalahan)

Output : Versi yang diperkecil.

Meskipun kode Anda harus dapat mengakomodasi semua input Python 2.7 yang valid, Anda perlu menguji skrip Anda terhadap sesuatu untuk membuktikan efektivitasnya.

Klik di sini untuk melihat contoh program.

Membuat masalah lebih mudah didekati

Jangan ragu untuk menggunakan atau memodifikasi kode apa pun yang ditemukan di dalam solusi saya (tercantum di bawah). Saya melakukan ini untuk membantu Anda memulai dengan penanganan penawaran dasar quote; Namun, Anda dapat memperluasnya ke lekukan, dan lain-lain.

Contoh cara untuk memperkecil Python

Semua ruang putih dapat diganti dengan jumlah minimum yang mungkin (saya akui bahwa dengan Python Anda dapat melakukan beberapa hal rumit dengan tab , tetapi saya akan menyerahkannya kepada Anda untuk memutuskan apakah akan menerapkannya atau tidak).

Contoh

Pengikut:

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

Bisa jadi:

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

Secara teknis, jika hanya ada satu baris di dalam satu loop, Anda dapat lebih menekannya:

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

Namun, ada cara lain Anda dapat meminimalkan ruang putih di Python:

Pengikut:

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

Bisa jadi:

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

Perhatikan, bahwa tidak perlu ruang antara 2dan for. Variabel, fungsi, dan kata kunci tidak dapat dimulai dengan angka. Jadi, juru bahasa Python tidak apa-apa <num><keyword>, tidak ada ruang. Anda juga harus memperhatikan bahwa tidak ada jarak antara )dan if.

Catatan, Anda tidak boleh mengubah output program! Begitu:

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

Pernyataan cetak di atas harus tetap sama karena menghilangkan ruang di antara 2dan isakan mengubah output.

Neil
sumber
Sidenote: tidak ada program yang dapat menghasilkan padanan terpendek dari program input sembarang, per diskusi ini
Leaky Nun
Ada melakukan beberapa alat python minifier sudah . Saya tidak berpikir pertanyaan ini dapat menerima solusi yang lebih baik daripada alat yang sudah keluar.
tsh
Apakah perubahan '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'menjadi '1'*100diizinkan? Perlu dilakukan karena perilaku yang sama?
l4m2

Jawaban:

2

Skor Python 2.7, 2013

Program ini dapat digunakan sebagai referensi, dan Anda diizinkan untuk mengambil kode berikut dan memodifikasinya lalu mempostingnya di solusi Anda sendiri.

Kalau dipikir-pikir, saya mungkin seharusnya menggunakan regex untuk penanganan kutipan juga, tapi saya pikir dalam kondisi saat ini mungkin cukup untuk melompati orang ke dalam masalah.

Mengapa saya memilih Python 2.7: Saya pikir akan lebih mudah untuk menguji apakah saya membuat program macet melalui execkata kunci.

Kode ini membuat program sebagai in.txt.

Saya pikir saya setidaknya harus mendapatkan bola bergulir untuk siapa pun yang ingin berpartisipasi dengan menulis parser kutipan (yang juga terjadi untuk menangani komentar) dan contoh singkat tentang bagaimana regex, ketika dikombinasikan dengan parser kutipan benar-benar dapat mengubah permainan dalam hal kompleksitas masalah ini.

Catatan: masih ada banyak ruang untuk perbaikan dalam minifier ini. Seperti Anda bisa bermain-main dengan lekukan, nama variabel, dan menghapus tanda kurung ketika sedang digunakan kata kunci saya, suka printatau 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)

Output dari program:

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
Neil
sumber