Compressione dei dati RLE per disegnare l'arte ASCII


11

Questa domanda si basa su ciò che mi è venuto in mente per rispondere a un'altra domanda .

A volte le domande qui pongono per disegnare un po 'di arte ASCII. Un modo semplice per archiviare i dati per l'arte è RLE (codifica di lunghezza di esecuzione) . Così:

qqqwwwwweeerrrrrtttyyyy

diventa:

3q5w3e5r3t4y

Ora per disegnare una grande arte ASCII potresti forse ottenere dati come questo (ignorando i nuovi caratteri di linea):

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)

I caratteri utilizzati per l'arte ASCII non saranno mai lettere minuscole o maiuscole o numeri, solo segni, segni e simboli, ma sempre nel set di caratteri ASCII stampabile.

Vuoi risparmiare un po 'di spazio in quella stringa, quindi sostituisci i numeri con il set di caratteri maiuscoli (essendo' A 'uguale a 1,' B 'è uguale a 2 fino a quando' Z 'è uguale a 26), perché non hai mai intenzione di ottieni più di 26 ripetizioni di un personaggio. Quindi ottieni:

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

(Character count: 34)

E infine noti che alcuni gruppi di (lettera + simbolo) si ripetono, quindi sostituisci i gruppi che compaiono 3 volte o più nella stringa dal set di caratteri minuscoli, nell'ordine o nell'aspetto nella stringa, ma memorizzando in un buffer il sostituzioni effettuate (nel formato "gruppo + carattere sostitutivo" per ciascuna sostituzione), lasciando il resto della stringa così com'è. Quindi i seguenti gruppi:

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

viene sostituito da 'a', 'b' e 'c', rispettivamente, perché non ci saranno mai più di 26 gruppi che si ripetono. Quindi finalmente ottieni:

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

(Character count: 9+24=33)

[L'ultimo passaggio salva solo 1 byte perché i gruppi che salvano effettivamente i caratteri dopo essere stati sostituiti sono quelli che appaiono 4 volte o più.]

La sfida

Data una stringa contenente i dati RLE per disegnare un'arte ASCII (con le restrizioni proposte), scrivi il programma / funzione / metodo più breve che puoi per comprimerlo come descritto. L'algoritmo deve stampare / restituire due stringhe: la prima contenente il dizionario utilizzato per la compressione e la seconda è la stringa compressa risultante. Puoi restituire le stringhe come una Tupla, una matrice, una Lista o qualsiasi altra cosa, nell'ordine dato.

Si noti che se la stringa non può essere compressa nel passaggio 2, l'algoritmo deve restituire una stringa vuota come primo valore restituito e il risultato del passaggio 1 come secondo valore restituito.

Non è necessario includere il risultato del passaggio 1 nei valori di output, li includo solo negli esempi a scopo di chiarimento.

Questo è , quindi può vincere la risposta più breve per ogni lingua!

Un altro caso di test

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
perché non otterrai mai più di 26 ripetizioni di un personaggio No. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Okx,

@Okx Non può mai essere così.
Erik the Outgolfer,

@Okx sì, nel mondo reale. Le regole sono inventate per un insieme limitato di arte ASCII.
Charlie,

2
In una vera implementazione, S,aT bK@cverrebbero probabilmente archiviati semplicemente S,T K@senza nominare esplicitamente i caratteri di sostituzione che possono essere banalmente dedotti da quello.
Arnauld,

@Arnauld hai perfettamente ragione, l'ho perso, ma ho intenzione di lasciare la domanda così com'è, nel caso in cui qualcuno abbia iniziato a scrivere la sua risposta.
Charlie,

Risposte:


3

JavaScript (ES6), 168 167 byte

Restituisce un array di due stringhe: [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``]

Casi test


3

Python 2 , 269 280 268 266 byte

Non c'è niente di speciale qui. Buona opportunità di usare alcune semplici espressioni regolari.

La prima versione non è riuscita per le stringhe contenenti caratteri speciali interpretati nella regex. La seconda versione (usando re.escape) funziona con tutti i casi di test. Quella correzione costava 11 byte.

La seconda versione non ha assegnato i caratteri di sostituzione in ordine, come richiesto nella specifica del problema, e come sottolineato da @CarlosAlejo. Quindi, tornando al tavolo da disegno.

Versione corretta, ulteriormente giocata a golf

  • -6 byte salvati non stampando l'output su due righe
  • +3 byte: passaggio alle sostituzioni di codice tramite una stringa per consentire di rispondere alla sfida come specificato.
  • -4 byte: poiché non sto più chiamando re.findall due volte, non ho bisogno di rinominarlo
  • -5 byte: passaggio da per loop a mentre loop.
  • -2 byte grazie a @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

Provalo online!


Ci sei quasi, nota che i gruppi nel secondo passaggio non vengono creati nell'ordine corretto (vedi esempio). I gruppi devono essere creati in ordine di apparizione, quindi il primo dovrebbe essere O,a.
Charlie,

@CarlosAlejo Non l'avevo notato come requisito, dal momento che le sostituzioni sono arbitrarie, da un punto di vista funzionale. I dizionari predefiniti di Python, un modo naturale per implementarlo, non sono ordinati. Dovrà prendere in considerazione altre possibili strutture di dati ....
CCB60

Non potresti salvare alcuni byte usando b=a=input()e n,s,p=96,'',0?
Compagno SparklePony,

\d+sarebbe una regex più breve da usare. Non supererai mai più di 26, quindi non c'è motivo di assicurarsi che siano specificamente 1-2 cifre. Inoltre, l'utilizzo re.escapesignifica che una stringa di base risulta replaceleggermente più corta: 253 byte
Valore inchiostro

0

Lua, 215 byte

Solo un bel po 'di corrispondenza del modello.

Penso che Lua sia sottovalutata quando si tratta di golf ... guarda tutte quelle affermazioni messe insieme!

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 byte

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

Speravo di trovare finalmente un uso per 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

Compresso al passaggio 2

Non compresso al passaggio 2


Python 2 , 246 byte

Intero secondo passo fatto in sostituzione di lambda di re.sub. Solo per divertimento.

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

Provalo online!


0

Perl 5 -pl , 81 byte

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

Provalo online!

Stampa la stringa codificata sulla prima riga, le triple sulla seconda riga


0

Rubino -p , 133 byte

gsub(/(\d+)(.)/){(64+$1.to_i).chr+$2}
c=?`;s=''
$_.scan(/(..)(?=.*\1.*\1)/){s+=$&+c.succ!if !s[$&]}
puts s.scan(/(..)(.)/){gsub$1,$2}

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.