Давайте напишем минификатор


14

Фон

Минифайеры, как правило, используются при обслуживании JavaScript в вашем веб-браузере. Обычно он используется для уменьшения количества байтов, которые должны быть отправлены. Экономия полосы пропускания полезна по очевидным причинам. Некоторые люди используют obfuscaters (которые намеренно затрудняют чтение кода), я не говорю о них.

Мы будем минимизировать Python 2

Я спорил о том, использовать ли JavaScript или Python для минимизации опыта, и я выбрал Python по двум причинам: пустое пространство имеет значение, и я думаю, что это добавит интересную динамику к проблеме. Кроме того, использование Python 2.7 обеспечит другую динамику, такую ​​как удаление лишних ()во время печати (т.е. print("Hello world")против 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приведет к изменению вывода.



Замечание: нет программы, которая могла бы выводить кратчайший эквивалент любой произвольной входной программы, в соответствии с этим обсуждением
Leaky Nun

Там делают быть некоторые питона Minifier инструменты уже . Я не думаю, что этот вопрос может получить лучшее решение, чем уже существующие инструменты.
ТШ

Меняется '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'в '1'*100разрешено? Требовать поступить так же, как поведение?
14 м2

Ответы:


2

Python 2.7, 2013 балл

Эта программа может быть использована в качестве справочной, и вам разрешено взять следующий код и изменить его, а затем опубликовать его в ваших собственных решениях.

Оглядываясь назад, возможно, мне следовало бы также использовать регулярные выражения для обработки цитат, но я думаю, что в текущем состоянии этого может быть достаточно, чтобы дать толчок людям к проблеме.

Почему я выбрал Python 2.7: я подумал, что будет проще проверить, вызвал ли я сбой программы через exec ключевое слово.

Этот код принимает программу как in.txt .

Я подумал, что должен, по крайней мере, набрать мяч для тех, кто хочет участвовать, написав анализатор цитат (который также обрабатывает комментарии) и краткий пример того, как регулярное выражение в сочетании с анализатором цитат может реально изменить игру с точки зрения сложность этой проблемы.

Примечание: в этом минифере еще есть много возможностей для улучшения. Как будто вы можете поиграть с отступами, именами переменных и удалением скобок, когда они используются, мои ключевые слова, например printили 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)

Вывод программы:

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.