Python Неизвестный поиск паттернов
Хорошо, в основном я хочу сжать файл, повторно используя код, а затем во время выполнения заменить отсутствующий код. То, что я придумал, действительно ужасно и медленно, по крайней мере, это работает. Проблема в том, что файл не имеет определенной структуры, например, 'aGVsbG8=\n', поскольку вы можете видеть его кодировку base64. Моя функция действительно медленная, потому что длина файла составляет 1700+, и она проверяет шаблоны на 1 символ за раз. Пожалуйста, помогите мне с новым лучшим кодом или, по крайней мере, помогите мне оптимизировать то, что я получил:). Добро пожаловать! Кстати, я уже пробовал библиотеки сжатия, но они не сжимали так хорошо, как моя уродливая функция.
def c_long(inp, cap=False, b=5):
import re,string
if cap is False: cap = len(inp)
es = re.escape; le=len; ref = re.findall; ran = range; fi = string.find
c = b;inpc = inp;pattern = inpc[:b]; l=[]
rep = string.replace; ins = list.insert
while True:
if c == le(inpc) and le(inpc) > b+1: c = b; inpc = inpc[1:]; pattern = inpc[:b]
elif le(inpc) <= b: break
if c == cap: c = b; inpc = inpc[1:]; pattern = inpc[:b]
p = ref(es(pattern),inp)
pattern += inpc[c]
if le(p) > 1 and le(pattern) >= b+1:
if l == []: l = [[pattern,le(p)+le(pattern)]]
elif le(ref(es(inpc[:c+2]),inp))+le(inpc[:c+2]) < le(p)+le(pattern):
x = [pattern,le(p)+le(inpc[:c+1])]
for i in ran(le(l)):
if x[1] >= l[i][1] and x[0][:-1] not in l[i][0]: ins(l,i,x); break
elif x[1] >= l[i][1] and x[0][:-1] in l[i][0]: l[i] = x; break
inpc = inpc[:fi(inpc,x[0])] + inpc[le(x[0]):]
pattern = inpc[:b]
c = b-1
c += 1
d = {}; c = 0
s = ran(le(l))
for x in l: inp = rep(inp,x[0],'{%d}' % s[c]); d[str(s[c])] = x[0]; c += 1
return [inp,d]
def decompress(inp,l): return apply(inp.format, [l[str(x)] for x in sorted([int(x) for x in l.keys()])])
2 ответа
Самый простой способ сжать данные в кодировке base64- сначала преобразовать их в двоичные данные - это уже сэкономит 25 процентов пространства хранения:
>>> s = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=\n"
>>> t = s.decode("base64")
>>> len(s)
37
>>> len(t)
26
В большинстве случаев вы можете сжать строку еще дальше, используя некоторый алгоритм сжатия, например t.encode("bz2")
или же t.encode("zlib")
,
Несколько замечаний о вашем коде: Есть много факторов, которые делают код трудным для чтения: непоследовательный пробел, чрезмерно длинные строки, бессмысленные имена переменных, недиоматический код и т. Д. Пример: Ваш decompress()
функция может быть эквивалентно написана как
def decompress(compressed_string, substitutions):
subst_list = [substitutions[k] for k in sorted(substitutions, key=int)]
return compressed_string.format(*subst_list)
Теперь уже гораздо более очевидно, что он делает. Вы могли бы пойти еще дальше: почему substitutions
словарь со строковыми ключами "0"
, "1"
так далее.? Мало того, что странно использовать строки вместо целых чисел - вам вообще не нужны ключи! Простой список подойдет, и decompress()
упростит до
def decompress(compressed_string, substitutions):
return compressed_string.format(*substitutions)
Вы можете подумать, что все это второстепенно, но если вы сделаете остальную часть своего кода одинаково читабельной, вы сами обнаружите ошибки в своем коде. (Есть ошибки - это сбой для "abcdefgabcdefg"
и много других строк.)
Обычно можно прокачать программу через алгоритм сжатия, оптимизированный для текста, а затем запустить его через exec
например,
code="""..."""
exec(somelib.decompress(code), globals=???, locals=???)
Это может быть тот случай, когда .pyc
/.pyo
файлы уже сжаты, и это можно проверить, создав файл с x="""aaaaaaaa"""
, затем увеличивая длину до x="""aaaaaaaaaaaaaaaaaaaaaaa...aaaa"""
и увидеть, если размер заметно меняется.