Kompresowanie danych RLE w celu narysowania sztuki ASCII


11

To pytanie opiera się na tym, co wymyśliłem, aby odpowiedzieć na inne pytanie .

Czasami pytania tutaj wymagają narysowania sztuki ASCII. Jednym prostym sposobem przechowywania danych dla sztuki jest RLE (kodowanie długości przebiegu) . Więc:

qqqwwwwweeerrrrrtttyyyy

staje się:

3q5w3e5r3t4y

Teraz, aby narysować dużą grafikę ASCII, być może otrzymujesz takie dane (ignorując nowe znaki wiersza):

19,20 3(4)11@1$20 11@19,15"4:20 4)19,4:20 11@
   ^^^
   Note that this is "20 whitespaces"

(Character count: 45)

Znaki używane w sztuce ASCII nigdy nie będą małymi lub wielkimi literami lub cyframi, a jedynie znaki, znaki i symbole, ale zawsze w zestawie znaków ASCII do wydruku.

Chcesz zaoszczędzić trochę miejsca w tym ciągu, więc zamieniasz cyfry na zestaw wielkich liter (wartość „A” równa się 1, „B” równa się 2, aż „Z” równa się 26), ponieważ nigdy nie zamierzasz uzyskaj ponad 26 powtórzeń postaci. Otrzymujesz:

S,T C(D)K@A$T K@S,O"D:T D)S,D:T K@

(Character count: 34)

I w końcu zauważasz, że niektóre grupy (litera + symbol) powtarzają się, więc zastępujesz grupy, które pojawiają się 3 lub więcej razy w ciągu przez zestaw małych liter, w kolejności lub pojawieniu się w ciągu, ale przechowując w buforze dokonane podstawienia (w formacie „grupa + char podstawienie” dla każdego podstawienia), a pozostała część łańcucha bez zmian. Więc następujące grupy:

S, (3 times) 
T  (4 times)
K@ (3 times)

zostaje zastąpione odpowiednio przez „a”, „b” i „c”, ponieważ nigdy nie będzie więcej niż 26 grup powtarzających się. W końcu otrzymujesz:

S,aT bK@c
abC(D)cA$bcaO"D:bD)aD:bc

(Character count: 9+24=33)

[Ostatni krok pozwala zaoszczędzić tylko 1 bajt, ponieważ grupy, które faktycznie zapisują znaki po zastąpieniu, pojawiają się 4 razy lub więcej.]

Wyzwanie

Biorąc pod uwagę ciąg znaków zawierający dane RLE do narysowania grafiki ASCII (z zaproponowanymi ograniczeniami), napisz najkrótszy program / funkcję / metodę, którą możesz skompresować zgodnie z opisem. Algorytm musi wydrukować / zwrócić dwa ciągi: pierwszy zawierający słownik używany do kompresji, a drugi to wynikowy skompresowany ciąg. Możesz zwrócić ciągi jako krotkę, tablicę, listę lub cokolwiek innego, w podanej kolejności.

Należy zauważyć, że jeśli ciąg nie może zostać skompresowany w kroku 2, algorytm musi zwrócić pusty ciąg jako pierwszą wartość zwracaną, a wynik kroku 1 jako drugą wartość zwracaną.

Nie musisz dołączać wyniku kroku 1 do wartości wyjściowych, po prostu uwzględniam je w przykładach w celu wyjaśnienia.

To jest , więc może wygrać najkrótsza odpowiedź dla każdego języka!

Kolejny przypadek testowy

Input:                   15,15/10$15,15/10"10$10"10$10"10$10"15,15/

Output of step 1:        O,O/J$O,O/J"J$J"J$J"J$J"O,O/

Final algorithm output:  O,aO/bJ$cJ"d
                         abcabdcdcdcdab

---

Input:                   15,15/10$15,15/10"

Output of step 1:        O,O/J$O,O/J"

Final algorithm output:  <empty string>
                         O,O/J$O,O/J"

1
ponieważ nigdy nie uzyskasz więcej niż 26 powtórzeń postaci Nie. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Okx

@Okx To nigdy nie może mieć miejsca.
Erik the Outgolfer

@Okx tak, w prawdziwym świecie. Zasady zostały jednak opracowane dla ograniczonego zestawu grafiki ASCII.
Charlie

2
W prawdziwej implementacji S,aT bK@cprawdopodobnie byłby przechowywany jako S,T K@bez wyraźnego nazewnictwa znaków podstawienia, które można w prosty sposób wydedukować z tego.
Arnauld

@Arnauld masz całkowitą rację, tęskniłem za tym, ale pozostawiam pytanie tak, jak jest, na wypadek, gdyby ktoś zaczął pisać jego / jej odpowiedź.
Charlie

Odpowiedzi:


3

JavaScript (ES6), 168 167 bajtów

Zwraca tablicę z dwóch ciągów: [dictionary, compressed_string].

s=>[(a=(s=s.replace(/\d+/g,n=>C(n|64),C=String.fromCharCode)).match(/../g)).map(v=>s.split(v)[a[v]||3]>=''?D+=v+(a[v]=C(i++)):0,i=97,D='')&&D,a.map(v=>a[v]||v).join``]

Przypadki testowe


3

Python 2 , 269 280 268 266 bajtów

Nie dzieje się tu nic szczególnego. Dobra okazja do użycia prostych wyrażeń regularnych.

Pierwsza wersja nie powiodła się w przypadku ciągów znaków specjalnych, które zostały zinterpretowane w wyrażeniu regularnym. Druga wersja (wykorzystująca re.escape) działa ze wszystkimi przypadkami testowymi. Ta korekta kosztuje 11 bajtów.

Druga wersja nie przypisywała znaków podstawienia w kolejności, zgodnie z wymaganiami specyfikacji problemu i jak wskazał @CarlosAlejo. Wróćmy do tablicy kreślarskiej.

Wersja poprawiona, dalej golfowa

  • -6 bajtów zapisanych przez brak drukowania danych wyjściowych w dwóch wierszach
  • +3 bajty: Przełączanie na podstawienia kodu za pomocą ciągu znaków, aby umożliwić spełnienie określonego wyzwania.
  • -4 bajty: Ponieważ nie dzwonię już ponownie do re.findall, nie muszę go zmieniać
  • -5 bajtów: przełączanie z pętli for na pętle while.
  • -2 bajty dzięki @Comrade Sparkle Pony
import re
S=re.sub
b=a=input()
for i in re.findall('\d{1,2}',a):
 b=S(i, chr(64+int(i)),b)
n,s,p=96,'',0
while p<len(b):
 c=b[p:p+2];f=b.count(c)
 if f>2and not c in s:n+=1;s+=c+chr(n)
 p+=2
p=0
while p<len(s):k=s[p:p+2];v=s[p+2];b=S(re.escape(k),v,b);p+=3
print s,b

Wypróbuj online!


Już prawie jesteś, zauważ, że grupy w drugim kroku nie są tworzone w odpowiedniej kolejności (patrz przykład). Grupy muszą być tworzone w kolejności wyświetlania, więc pierwsza powinna być O,a.
Charlie

@CarlosAlejo Nie zauważyłem tego jako wymogu, ponieważ podstawienia są arbitralne z funkcjonalnego punktu widzenia. Domyślne słowniki Pythona, naturalny sposób na wdrożenie tego, są nieuporządkowane. Będę musiał rozważyć inne możliwe struktury danych ....
CCB60,

Nie możesz zapisać niektórych bajtów za pomocą b=a=input()i n,s,p=96,'',0?
Towarzysz SparklePony,

\d+byłoby krótszym wyrażeniem regularnym w użyciu. I tak nigdy nie przekroczysz 26, więc nie ma powodu, aby mieć dokładnie 1-2 cyfry. Ponadto użycie re.escapeoznacza, że ​​podstawowy ciąg znaków replacekończy się nieco krócej: 253 bajtów
tusz wartościowy

0

Lua, 215 bajtów

Po prostu trochę dopasowania wzoru.

Myślę, że Lua jest niedoceniana, jeśli chodzi o grę w golfa ... spójrz na te wszystkie wypowiedzi ułożone razem!

g,c=string.gsub,string.char
u=g(arg[1],"%d%d?",function(n)return c(n+64)end)l,d=97,""g(u,"..",function(m)n,e=0,g(m,".", "%%%0")g(u,e,function()n=n+1 end)if n>2 then
l,s=l+1,c(l)d,u=d..m..s,g(u,e,s)end
end)print(u,d)

0

Python 2 , 186 bajtów

from re import*
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
Q=[]
for p in findall('[A-Z].',S):
 if S.count(p)>2:a=chr(len(Q)+97);Q+=[p+a];S=sub(escape(p),a,S)
print''.join(Q),S

Miałem nadzieję, że w końcu znajdę zastosowanie dla re.subn: C

# first step - convert all numbers to uppercase letters
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
# empty list to hold encoding of second step
Q=[]
# find every encoded pair (uppercase letter and some char)
for p in findall('[A-Z].',S):
 # if it occures 3 or move times
 if S.count(p)>2:
  # get lowercase letter to substitute with
  a=chr(len(Q)+97)
  # store encoding into list
  Q+=[p+a]
  # update string - substitute pair with lowercase letter
  S=sub(escape(p),a,S)
# output
# encodings of second step, space, result
# if nothing was compressed at step 2, space would prepend result (of step 1)
print''.join(Q),S

Kompresowany w kroku 2

Bez kompresji w kroku 2


Python 2 , 246 bajtów

Cały drugi krok wykonano w repl lambda z re. Dla żartu.

from re import*
Q=[]
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
S=sub('[A-Z].',lambda m:(lambda m:S.count(m)>2and(m in Q or not Q.append(m))and chr(Q.index(m)+97)or m)(m.group(0)),S)
print''.join(Q[i]+chr(i+97)for i in range(len(Q))),S

Wypróbuj online!


0

Perl 5 -pl , 81 bajtów

s/\d+/chr$&+64/ge;$b=a;for$a(/([A-Z].)(?=.*\1.*\1)/g){s/\Q$a/$b/g&&($\.=$a.$b++)}

Wypróbuj online!

Drukuje zakodowany ciąg w pierwszym wierszu, a trzykrotnie w drugim wierszu


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.