มาเขียน Minifier กัน


14

พื้นหลัง

โดยทั่วไปจะใช้ตัวขยายขนาดเล็กเมื่อแสดง JavaScript ในเว็บเบราว์เซอร์ของคุณ โดยทั่วไปจะใช้เพื่อลดจำนวนไบต์ที่ต้องส่ง การประหยัดแบนด์วิดท์มีประโยชน์สำหรับเหตุผลที่ชัดเจน บางคนใช้ obfuscaters (ซึ่งตั้งใจทำให้อ่านรหัสยากขึ้น) ฉันไม่ได้พูดถึงสิ่งเหล่านั้น

เราจะลดขนาด Python 2

ฉันกำลังถกเถียงกันว่าจะใช้ JavaScript หรือ Python สำหรับประสบการณ์การลดขนาดหรือไม่และฉันตัดสินใจใช้ Python ด้วยเหตุผลสองประการ: พื้นที่สีขาวมีความสำคัญและฉันคิดว่านั่นจะเพิ่มปัญหาไดนามิกที่น่าสนใจ นอกจากนี้การใช้ Python 2.7 จะให้ไดนามิกอื่นเช่นลบฟุ่มเฟือย()ระหว่างการพิมพ์ (เช่นprint("Hello world")vs. print"Hello world") โดยส่วนตัวฉันชอบที่จะเปิดเป็นภาษาใดก็ได้ แต่สำหรับบางภาษากระบวนการนี้จะไม่สมเหตุสมผล และภาษาใดที่คุณตัดสินใจที่จะลดขนาดจะส่งผลกระทบโดยตรงต่อคะแนนของคุณ (และหากภาษานั้นสามารถลดขนาดได้)

รายละเอียด

เป้าหมายของคุณคือการแก้ไขโค้ดในแบบที่จะไม่เปลี่ยนเป็นฟังก์ชั่น แน่นอนคุณอาจเปลี่ยนชื่อตัวแปร (ภายในโปรแกรมลดขนาด) ของคุณตราบใดที่มันไม่มีผลต่อการส่งออก (ติดตามขอบเขต ) แม้ว่าฉันจะให้โปรแกรมเฉพาะแก่คุณโปรดอย่าปรับให้เหมาะสมสำหรับกรณีทดสอบเนื่องจากช่องโหว่มาตรฐานทั้งหมดถูกห้าม

คะแนน : ความยาวของโปรแกรมหลังจากที่คุณย่อขนาดให้เล็กที่สุดแล้ว

อินพุต : โปรแกรม Python 2.7 ใด ๆ (ที่ไม่มีข้อผิดพลาด)

เอาต์พุต : เวอร์ชันที่ย่อเล็กสุด

แม้ว่ารหัสของคุณจะสามารถรองรับการป้อนข้อมูล Python 2.7 ที่ถูกต้องทั้งหมดได้ แต่ก็จำเป็นต้องทดสอบสคริปต์ของคุณกับบางอย่างเพื่อพิสูจน์ว่ามีประสิทธิภาพ

คลิกที่นี่เพื่อดูตัวอย่างโปรแกรม

ทำให้ปัญหาเข้าถึงได้ง่ายขึ้น

อย่าลังเลที่จะใช้หรือแก้ไขรหัสใด ๆ ที่พบในโซลูชันของฉัน ฉันทำสิ่งนี้เพื่อให้คุณเริ่มต้นด้วยการจัดการใบเสนอราคาเบื้องต้น อย่างไรก็ตามคุณสามารถขยายเป็นเยื้องและอื่น ๆ

ตัวอย่างวิธีในการลดขนาด Python

พื้นที่สีขาวทั้งหมดอาจถูกแทนที่ด้วยจำนวนเงินขั้นต่ำที่เป็นไปได้ (ฉันรับทราบว่าใน Python คุณสามารถทำสิ่งที่ยุ่งยากด้วยแท็บได้ แต่ฉันจะปล่อยให้คุณตัดสินใจว่าจะใช้หรือไม่)

ตัวอย่าง

ดังต่อไปนี้:

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

อาจจะเป็น:

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

ในทางเทคนิคหากมีเพียงหนึ่งบรรทัดในลูปคุณสามารถบีบอัดมันได้มากขึ้น:

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

อย่างไรก็ตามมีวิธีอื่นที่คุณสามารถย่อขนาดพื้นที่ว่างใน Python ได้:

ดังต่อไปนี้:

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

อาจจะเป็น:

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

ทราบว่ามีความจำเป็นสำหรับช่องว่างระหว่างไม่มีและ2 forตัวแปรฟังก์ชันและคำหลักไม่สามารถเริ่มต้นด้วยตัวเลขได้ ดังนั้นล่าม Python ก็โอเคกับ<num><keyword>ไม่มีที่ว่าง คุณควรทราบว่าไม่จำเป็นต้องเว้นวรรคระหว่าง)และifและ

หมายเหตุคุณต้องไม่เปลี่ยนผลลัพธ์ของโปรแกรม! ดังนั้น:

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

ข้อความสั่งพิมพ์ด้านบนควรคงเดิมเพราะลบช่องว่างระหว่าง2และisจะแก้ไขผลลัพธ์



Sidenote: ไม่มีโปรแกรมใดที่สามารถให้ผลลัพธ์ที่สั้นที่สุดเทียบเท่ากับโปรแกรมอินพุตใด ๆ ตามการสนทนานี้
Leaky Nun

มีไม่เป็นบางเครื่องมือหลาม minifier แล้ว ฉันไม่คิดว่าคำถามนี้อาจได้รับทางออกที่ดีกว่าเครื่องมือที่มีอยู่แล้ว
tsh

มีการเปลี่ยนแปลง'1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'เข้า'1'*100ได้รับอนุญาต? ต้องทำตามพฤติกรรมเหมือนกันไหม?
l4m2

คำตอบ:


2

Python 2.7, 2013 คะแนน

โปรแกรมนี้สามารถใช้เป็นข้อมูลอ้างอิงและคุณได้รับอนุญาตให้ใช้รหัสต่อไปนี้และแก้ไขมันแล้วโพสต์ในโซลูชันของคุณเอง

ในการเข้าใจถึงปัญหาหลังเก่าฉันอาจใช้ regex ในการจัดการใบเสนอราคาด้วย แต่ฉันคิดว่าในสถานะปัจจุบันมันอาจจะเพียงพอที่จะเริ่มต้นคนให้เป็นปัญหา

ทำไมฉันถึงเลือก Python 2.7: ฉันคิดว่ามันจะง่ายกว่าที่จะทดสอบเพื่อดูว่าฉันทำให้โปรแกรมขัดข้องผ่านทางexecคำหลักหรือไม่

in.txtรหัสนี้การบริโภคโปรแกรมเป็น

ฉันคิดว่าอย่างน้อยฉันควรจะได้รับลูกบอลกลิ้งสำหรับใครก็ตามที่ต้องการมีส่วนร่วมโดยการเขียนคำพูดแยกวิเคราะห์ ความซับซ้อนของปัญหานี้

หมายเหตุ:ยังมีพื้นที่เหลือเฟือสำหรับการปรับปรุงเครื่องขยายขนาดนี้ เช่นเดียวกับที่คุณสามารถเล่นรอบกับเยื้องชื่อตัวแปรและลบวงเล็บเมื่อพวกเขากำลังถูกนำมาใช้คำหลักของฉันเหมือนหรือprintyield

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)

ผลลัพธ์ของโปรแกรม:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.