Python 781 731 605 579 Chars
Ada lebih banyak dan lebih banyak jawaban yang lebih baik dari ketika saya pertama kali melihat ini, tetapi saya membuang banyak waktu pada skrip python saya jadi saya akan mempostingnya dengan cara apa pun, akan luar biasa untuk melihat saran untuk memperpendeknya,
Sunting: berkat saran Ed H, 2 karakter dicincang, untuk melangkah lebih jauh saya mungkin harus merestrukturisasi banyak hal di sini yang akan memakan waktu
s="e |nd|-We| a|-(Ooh|N| what|ive| go|ay it-|I|er|G|o |make5 |D| th| othH |A| tF|ing |nna |tell|'s been|'rS|-You|-N4| know|L5 up|PR | you|evHK>| how I'm feeling-|O, g7)|O)9gL, n4gL-(G7)|-I just wa>=53Gotta EuRHstaR-.|Q've8n eachBfor sFlong:r heart<Pch?but:;toFshy@sJInsidSwSboth8M<K?onQ8CSgame6we;go>plJ|9g79let5 down9runProuR6desHt59Ecry9sayKodbye9=P lie6hurt5-|\n|Q;nFstrangHs@love:8CSrules6sFdFI-A full commitment'sM I'mCink?of: wouldn't getCis fromPnyBguy0/AR if5Psk me3Don't = me5;toFbliR@see-..2211-/0..";i=83
exec"x,s=s.split('|',1);s=s.replace(chr(i),x);i-=1"*39
print s
Setelah pertama kali saya menghasilkan string secara manual (sangat membosankan), saya menulis sebuah fungsi untuk secara rekursif menemukan penggantian pola yang paling menguntungkan (pada langkah itu), yang memberi saya solusi tetapi ternyata meningkatkan ukurannya sebesar 10 karakter.
Jadi, saya membuat algoritma saya sedikit kurang serakah dengan alih-alih melakukan peringkat akhir hanya pada 'karakter dikurangi', peringkat pada fungsi 'karakter berkurang', 'panjang pola' dan 'jumlah pola'
panjang pola = jumlah panjang = jumlah
rank = [(length-1)*count - length - 2] + lengthWeight * length + countWeight * count
Kemudian saya meminta laptop saya yang buruk untuk berjalan tanpa batas, memberikan nilai acak ke lengthWeight
dan countWeight
dan mendapatkan ukuran kompresi akhir yang berbeda, dan menyimpan data untuk ukuran kompresi minimum dalam file
Dalam setengah jam atau lebih itu muncul dengan string di atas (saya mencoba untuk mengotak-atik lebih jauh untuk melihat apakah saya dapat mempersingkat kode), dan itu tidak akan lebih rendah, saya kira saya kehilangan sesuatu di sini.
inilah kode saya untuk itu, juga max_pattern
sangat lambat (Catatan: kode mengeluarkan string yang mirip dengan bentuk di versi saya sebelumnya dari solusi, saya secara manual bekerja melewatinya untuk mendapatkan bentuk saat ini, secara manual maksud saya, secara manual di shell python)
import itertools
global pretty
global split
split = False
pretty = False
# try to keep as much visibility as possible
def prefrange():
return range(32,127) + ([] if pretty else ([10, 9, 13] + [x for x in range(32) if x not in (10, 9, 13)] + [127]))
def asciichr():
return [chr(x) for x in prefrange()]
def max_pattern(s, o, lenw, numw):
l = len(s)
patts = []
for c in range(l/2+1,1,-1):
allsub = [s[i:i+c] for i in range(0, l, c)]
subcounts = [[a, s.count(a)] for a in allsub if len(a) == c]
repeats = [(x, y, ((c-o)*y - o*2 - c)) for x, y in subcounts if y > 1]
ranks = [(x, y, (z + lenw*c + numw*y)) for x,y,z in repeats if z > 0]
patts = patts + ranks
try:
return sorted(patts, key=lambda k: -k[2])[0]
except:
return None
def sep():
return '~~' if pretty else chr(127) + chr(127)
def newcharacter(s):
doable = [x for x in asciichr() if x not in s]
if len(doable) == 0:
doable = list(set(x+y for x in asciichr() for y in asciichr() if x+y not in s and x+y != sep()))
if len(doable) == 0:
return None
return doable[0]
def joined(s, l):
one = [x for x in l if len(x)==1]
two = [x for x in l if len(x)==2]
return ''.join(reversed(two)) + sep() + ''.join(reversed(one)) + sep() + s
def compress(s, l=[], lenw=0, numw=0):
newchr = newcharacter(s)
if newchr == None:
if not l:
return s
return joined(s,l)
else:
ptn = max_pattern(s, len(newchr), lenw, numw)
if ptn == None:
if not l:
return s
return joined(s, l)
s = s.replace(ptn[0], newchr)
s = ptn[0] + newchr + s
l.append(newchr)
return compress(s, l, lenw, numw)
def decompress(s):
lst2, lst, s = s.split(sep(),2)
li = [lst2[i:i+2] for i in xrange(0, len(lst2), 2)]+list(lst)
for c in li:
x, s = s.split(c, 1)
s = s.replace(c, x)
return s
def test(times):
import random
rnd = random.random
tested = {(1001, 1001): (10000, 10, False),}
org = open('text').read()
minfound = 1000
for i in xrange(times):
l,n = 1001,1001
while (l,n) in tested:
# i guess this would be random enough
xr = lambda: random.choice((rnd(), rnd()+rnd(), rnd()-rnd(), rnd()*random.choice((10,100,1000)), -1*rnd()*random.choice((10,100,1000)),))
n = xr()
l = xr()
sm = compress(org, l=[], lenw=l, numw=n)
try:
dc = decompress(sm)
except:
tested[l,n] = (len(sm), len(sm)/float(len(org)), 'err')
continue
tested[l,n] = (len(sm), len(sm)/float(len(org)), dc==org)
if len(sm) < minfound:
minfound = len(sm)
open('min.txt','a').write(repr(tested[l,n])+'\n')
print '~~~~~~~!!!!!!! New Minimum !!!!!!!~~~~'
return tested
if __name__ == '__main__':
import sys
split = False
try:
if sys.argv[2] == 'p':
pretty = True
except:
pretty = False
org = open(sys.argv[1]).read()
try:
l=float(sys.argv[3])
n=float(sys.argv[4])
except:
l,n=0,0
sm = compress(org,lenw=l,numw=n)
print 'COMPRESSED -->'
print sm, len(sm)
#open('new.py','w').write(sm)
print len(sm)/float(len(org))
print 'TRYING TO REVERT -->'
dc = decompress(sm)
#print dc
print dc==org