Bir Minifier yazalım


14

Arka fon

Küçültücüler, genellikle Web Tarayıcınıza JavaScript sunarken kullanılır. Genellikle gönderilmesi gereken bayt sayısını azaltmak için kullanılır. Bant genişliğinin kaydedilmesi bariz nedenlerle yararlıdır. Bazı insanlar obfuscaters (kasıtlı olarak kodu okumayı zorlaştırır) kullanır, ben bunlardan bahsetmiyorum.

Python 2'yi küçültecağız

Küçültme deneyimi için JavaScript veya Python kullanıp kullanmayacağımı tartışıyordum ve iki nedenden dolayı Python'a karar verdim: beyaz alan önemlidir ve bence bu ilginç bir dinamik sorunu ekleyecektir. Buna ek olarak, Python 2.7 kullanmak ()baskı sırasında gereksiz kaldırmak gibi başka bir dinamik sağlayacaktır (örn. print("Hello world")Vs. print"Hello world"). Şahsen, herhangi bir dile açmayı tercih ederdim, ancak bazı diller için bu süreç pek mantıklı değil. Ve hangi dili küçültmeye karar verdiğiniz, puanınızı doğrudan etkiler (ve dil bile küçültülüp küçülemeyebilir).

gözlük

Amacınız kodu yalnızca işlevselliğini hiçbir şekilde değiştirmeyecek şekilde değiştirmek. Elbette, çıktıyı etkilemediği sürece ( kapsamı takip edin) değişken adlarını (küçültme programınızın içinde ) değiştirebilirsiniz. Size belirli bir program veriyorum, ancak tüm standart boşlukların yasak olduğu için lütfen test durumu için optimizasyon yapmayın .

Puan : Programın küçültülmesinden sonraki uzunluğu.

Girdi : Herhangi bir Python 2.7 programı (hata içermeyen)

Çıktı : Küçültülmüş bir sürüm.

Kodunuzun tüm geçerli Python 2.7 girişlerini karşılayabilmesine rağmen, etkinliğini kanıtlamak için komut dosyanızı bir şeye karşı test etmeniz gerekir.

Örnek programı görüntülemek için buraya tıklayın .

Sorunu daha ulaşılabilir kılmak

Çözümümün içinde bulunan herhangi bir kodu (aşağıda listelenmiştir) kullanmaktan veya değiştirmektan çekinmeyin. Ben teklif temel teklif işleme ile başlamak için bunu yaptım; ancak girintiye vb. genişletebilirsiniz.

Python'u küçültmenin örnek yolları

Tüm beyaz boşluk mümkün olan en düşük miktarla değiştirilebilir (Python'da sekmelerle bazı zor şeyler yapabileceğinizi kabul ediyorum , ancak bunu uygulamaya ya da uygulamamaya karar vermek için size bırakacağım).

Misal

Devamındaki:

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

Olabilirdi:

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

Teknik olarak, bir döngü içinde sadece bir çizgi varsa, onu daha da sıkıştırabilirsiniz:

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

Ancak, Python'daki beyaz boşluğu küçültmenin başka bir yolu var:

Devamındaki:

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

Olabilirdi:

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

2Ve arasında bir boşluğa gerek olmadığını unutmayın for. Değişken, işlevleri ve anahtar olamaz bir rakamla başlayamaz. Yani, Python yorumlayıcısı sorun değil <num><keyword>, boşluk yok. Ayrıca )ve arasında bir boşluk olmaması gerektiğini de unutmamalısınız if.

Not, programın çıktısını değiştirmemelisiniz! Yani:

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

Yukarıdaki baskı deyimi arasındaki boşluğu kaldırarak çünkü aynı kalmalıdır 2ve isçıkışını değiştirir.



Sidenote: bu tartışma başına herhangi bir keyfi girdi programının en kısa eşdeğerini verebilecek bir program yoktur
Leaky Nun

Zaten bazı python minifier araçları var . Bu sorunun zaten araçlardan daha iyi bir çözüm alabileceğini düşünmüyorum.
tsh

Değişiyor '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'içine '1'*100izin? Davranış aynı olduğundan yapmak ister misiniz?
l4m2

Yanıtlar:


2

Python 2.7, 2013 puanı

Bu program referans olarak kullanılabilir ve aşağıdaki kodu alıp değiştirip kendi çözümlerinizde yayınlamanıza izin verilir.

Gez, belki de teklif işleme için regex kullanmalıydım, ama şu anki durumunda insanları problemin içine atlamak için yeterli olabilir.

Neden Python 2.7'yi seçtim: Programın execanahtar kelime yoluyla kilitlenip kilitlenmediğini test etmenin daha kolay olacağını düşündüm .

Bu kod programı olarak alır in.txt.

En azından bir teklif ayrıştırıcısı yazarak katılmak isteyenler için topu yuvarlamam gerektiğini düşündüm (bu da yorumları işlemektedir) ve teklif ayrıştırıcısıyla birleştirildiğinde oyunu gerçekten açısından nasıl değiştirebileceğine dair kısa bir örnek bu sorunun karmaşıklığı.

Not: Bu madencilikte hala iyileştirilmesi gereken çok şey var. Onlar gibi benim kelime kullanıyorlarsa zaman girinti, değişken adları ve parantez çıkarılması da oynayabilir gibi printya 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)

Program çıktısı:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.