Codifica Base85


10

La sfida

Scrivi un programma che può prendere l'input di una stringa a riga singola contenente qualsiasi carattere stampabile ASCII e produrre la stessa stringa codificata in Base85 (usando una convenzione big-endian). Si può presumere che l'input sarà sempre di ≤ 100 caratteri.


Una guida a Base85

  • Quattro ottetti sono codificati in (di solito) cinque caratteri Base85.

  • I caratteri Base85 vanno da !a u(ASCII 33 - 117) e z(ASCII 122).

  • Per codificare, esegui continuamente la divisione per 85 sui quattro ottetti (un numero a 32 bit) e aggiungi 33 al resto (dopo ogni divisione) per ottenere il carattere ASCII per il valore codificato. Ad esempio, la prima applicazione di questo processo produce il carattere più a destra nel blocco codificato.

  • Se un set di quattro ottetti contiene solo byte nulli, vengono codificati come zanziché !!!!!.

  • Se l'ultimo blocco è più corto di quattro ottetti, è riempito con byte null. Dopo la codifica, lo stesso numero di caratteri aggiunti come riempimento, viene rimosso dalla fine dell'output.

  • Il valore codificato deve essere preceduto <~e seguito da ~>.

  • Il valore codificato non deve contenere spazi bianchi (per questa sfida).


Esempi

In: easy
Out: <~ARTY*~>

In: test
Out: <~FCfN8~>

In: code golf
Out: <~@rGmh+D5V/Ac~>

In: Programming Puzzles
Out: <~:i^JeEa`g%Bl7Q+:j%)1Ch7Y~>

Il frammento seguente codificherà un determinato input in Base85.


3
Sono confuso sul perché, dato che limiti l'ingresso in ASCII stampabile, usi quindi byte come sinonimo di ottetto e non consenti byte a 7 bit.
Peter Taylor,

L'endianness dovrebbe essere specificato. Un blocco [0,1,2,3] viene convertito in un numero a 32 bit come 0x0123 o 0x3210?
edc65,

@ edc65 big endian secondo il link di Wikipedia
Level River St

3
@steveverrill grazie. Questo dovrebbe essere nel testo della sfida e non in un collegamento esterno. Almeno ora è in un commento
edc65,

Se l'input può contenere solo caratteri stampabili, come potrebbe contenere quattro byte null?
Luis Mendo,

Risposte:


9

CJam, 43 39 35 byte

"<~"q4/{:N4Ue]256b85b'!f+}/N,)<"~>"

Provalo online nell'interprete CJam .

Come funziona

"<~"      e# Push that string.
q4/       e# Read all input from STDIN and split it into chunks of length 4.
{         e# For each chunk:
  :N      e#   Save it in N.
  4Ue]    e#   Right-pad it with 0's to a length of 4.
  256b85b e#   Convert from base 256 to base 85.
  '!f+    e#   Add '!' to each base-85 digit.
}/        e#
N,)       e# Push the length of the last unpadded chunk, plus 1.
<         e# Keep that many chars of the last encoded chunk.
"~>"      e# Push that string.

Se l'input era vuoto, N,)verrà applicato alla stringa "<~". Poiché Ninizialmente contiene un singolo carattere, l'output sarà corretto.

Non abbiamo a che fare con z o pad i blocchi codificati alla lunghezza 5, poiché l'input conterrà solo caratteri ASCII stampabili.


3
Questa soluzione assomiglia sospettosamente alla versione Base85 di una stringa ASCII (vedi l'ultimo esempio in questione). Aspetta ...
ojdo,

1
@odjo: ci sono alcuni caratteri non validi nel codice CJam, il più vicino che ho è questo link dell'interprete
CJam

@ojdo perché la sfida è proprio questa:a program that can take an input of a single-line string containing any ASCII printable characters,...
edc65

5

Python 3, 71 byte

from base64 import*
print(a85encode(input().encode(),adobe=1).decode())

Non ho mai giocato a golf in Python, quindi questo è probabilmente non ottimale.

Grazie a @ZachGates per giocare a golf con 3 byte!


1
È possibile utilizzare input().encode()invece di str.encode(input())salvare 3 byte.
Zach Gates,

@ZachGates Grazie! Tutta quella en- / decodifica mi sta ancora uccidendo.
Dennis,

2

Python 2, 193 162 byte

from struct import*
i=raw_input()
k=4-len(i)%4&3
i+='\0'*k
o=''
while i:
 b,=unpack('>I',i[-4:]);i=i[:-4]
 while b:o+=chr(b%85+33);b/=85
print'<~%s~>'%o[k:][::-1]

Questo è il mio primo codice golf, quindi sono sicuro che c'è qualcosa di sbagliato nel mio approccio. Volevo anche implementare effettivamente base85 piuttosto che chiamare semplicemente la funzione di libreria. :)


Questo è 181 byte. Non dimenticare di rimuovere la nuova riga che IDLE aggiunge al tuo codice quando salvi (se stai utilizzando IDLE). Inoltre, non si chiama mai la funzione o si ottiene l'input dell'utente, quindi non fa nulla quando lo si esegue.
Zach Gates,

Non ero sicuro se dovesse essere una funzione o leggere l'I / O o cosa ... dovrebbe leggere stdin e stampare stdout? (Ancora una volta, non ho mai fatto golf in codice prima ...)
David,

Benvenuto in Programmazione di puzzle e codice golf! Sembra esserci un problema con lunghezze di input che non sono divisibili per 4 (ultimi 2 casi di test). La riga 3 dovrebbe leggere [:4+len(s)/4*4]e nessun carattere viene rimosso dalla fine dell'output.
Dennis,

Credo di aver risolto i problemi (e purtroppo l'ho allungato). Cercando di ottimizzare di più ...
David,

È possibile trasformare il vostro secondo whileciclo in uno come come questo: while b:d=chr(b%85+33)+d;b/=85. Puoi anche rimuovere lo spazio tra la tua printistruzione e la stringa. Inoltre, rimuovere lo spazio tra gli argomenti passati s.unpack.
Zach Gates,

2

Ottava, 133 131 byte

Grazie a @ojdo per avermi suggerito di prendere input da argv piuttosto che da stdin, salvandomi 2 byte.

function g(s) p=mod(-numel(s),4);s(end+1:end+p)=0;disp(['<~' dec2base(swapbytes(typecast(s,'uint32')),'!':'u')'(:)'(1:end-p) '~>'])

Ungolfed:

function g(s)             %// function header
p=mod(-numel(s),4);       %// number of missing chars until next multiple of 4
s(end+1:end+p)=0;         %// append p null characters to s
t=typecast(s,'uint32');   %// cast each 4 char block to uint32
u=swapbytes(t);           %// change endian-ness of uint32's
v=dec2base(u,'!':'u');    %// convert to base85
w=v'(:)'(1:end-p);        %// flatten and truncate resulting string
disp(['<~' w '~>']);      %// format and display final result

Ho pubblicato il codice su ideone . La funzione autonoma non richiede e enddichiarazione, ma poiché ideone ha la funzione e lo script chiamante nello stesso file richiede un separatore.

Non sono ancora riuscito a capire come stdinlavorare su ideone. Se qualcuno lo sa, sono ancora interessato, quindi per favore lasciami un commento.

Output di esempio da ideone :

easy
<~ARTY*~>
test
<~FCfN8~>
code golf
<~@rGmh+D5V/Ac~>
Programming Puzzles
<~:i^JeEa`g%Bl7Q+:j%)1Ch7Y~>

Perché non usare solo argv()? La descrizione dell'attività non sembra richiedere l'input di lettura da stdin.
ojdo,

Molto bella! Quindi dec2basein Octave sono consentite basi superiori a 36?
Luis Mendo,

Come dice il doc (e il messaggio di errore): l'argomento BASEdeve essere un numero compreso tra 2 e 36 o una stringa di simboli . Qui, l'espressione 'i':'u'espande la stringa di 85 caratteri !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuche funge da base.
ojdo,

@ojdo In tal caso, dovrei renderlo una funzione e forse salvare un paio di byte.
becher

1
@beaker Lo fa. Non solo la limitazione a 36, ​​ma il fatto che le cifre sono necessariamente 0 ... 9ABC, quindi c'è un salto nei codici ASCII
Luis Mendo

1

Matlab, 175 byte

s=input('','s');m=3-mod(numel(s)-1,4);s=reshape([s zeros(1,m)]',4,[])';t=char(mod(floor(bsxfun(@rdivide,s*256.^[3:-1:0]',85.^[4:-1:0])),85)+33)';t=t(:)';['<~' t(1:end-m) '~>']

Esempio:

>> s=input('','s');m=3-mod(numel(s)-1,4);s=reshape([s zeros(1,m)]',4,[])';t=char(mod(floor(bsxfun(@rdivide,s*256.^[3:-1:0]',85.^[4:-1:0])),85)+33)';t=t(:)';['<~' t(1:end-m) '~>']
code golf
ans =
<~@rGmh+D5V/Ac~>

1

PHP, 181 byte

foreach(str_split(bin2hex($argn),8)as$v){for($t="",$d=hexdec(str_pad($v,8,0));$d;$d=$d/85^0)$t=chr($d%85+33).$t;$r.=str_replace("!!!!!",z,substr($t,0,1+strlen($v)/2));}echo"<~$r~>";

Versione online

allargato

foreach(str_split(bin2hex($argn),8)as$v){
    for($t="",$d=hexdec(str_pad($v,8,0));$d;$d=$d/85^0)
      $t=chr($d%85+33).$t;
    $r.=str_replace("!!!!!",z,substr($t,0,1+strlen($v)/2));
}
echo"<~$r~>";

1

Bash puro, ~ 738

Prima l'encoder (qualcosa da giocare):

#!/bin/bash
# Ascii 85 encoder bash script
LANG=C

printf -v n \\%o {32..126};printf -v n "$n";printf -v m %-20sE abtnvfr;p=\<~;l()
{ q=$(($1<<24|$2<<16|$3<<8|$4));q="${n:1+(q/64#378iN)%85:1}${n:1+(q/614125)%85:1
}${n:1+(q/7225)%85:1}${n:1+(q/85)%85:1}${n:1+q%85:1}";};k() { ((${#p}>74))&&ech\
o "${p:0:75}" && p=${p:75};};while IFS= read -rd '' -n 1 q;do [ "$q" ]&&{ print\
f -v q "%q" "$q";case ${#q} in 1|2)q=${n%$q*};o+=($((${#q}+32)));;7)q=${q#*\'\\}
o+=($((8#${q%\'})));;5)q=${q#*\'\\};q=${m%${q%\'}*};o+=($((${#q}+07)));;esac;}||
o+=(0);((${#o[@]}>3))&&{ [ "${o[*]}" = "0 0 0 0" ]&& q=z|| l ${o[@]};p+="${q}";k
o=(); };done;[ "$o" ]&&{ f=0;for((;${#o[@]}<4;)){ o+=(0);((f++));};((f==0))&&[ \
"${o[*]}" = "0 0 0 0" ]&&q=z||l ${o[@]};p+="${q:0:5-f}";};p+="~>";k;[ "$p" ]&&e\
cho "$p"

test:

for word in easy test code\ golf Programming\ Puzzles ;do
    printf "%-24s" "$word:"
    ./enc85.sh < <(printf "$word")
  done
easy:                   <~ARTY*~>
test:                   <~FCfN8~>
code golf:              <~@rGmh+D5V/Ac~>
Programming Puzzles:    <~:i^JeEa`g%Bl7Q+:j%)1Ch7Y~>

e decodificatore ora:

#!/bin/bash
# Ascii 85 decoder bash script
LANG=C

printf -v n "\%o" {33..117};printf -v n "$n";o=1 k=1;j(){ read -r q||o=;[ "$q" \
]&&[ -z "${q//*<~*}" ]&&((k))&&k= q="${q#*<~}";m+="$q";m="${m%~>*}";};l(){ r=;f\
or((i=0;i<${#1};i++)){ s="${1:i:1}";case "$s" in "*"|\\|\?)s=\\${s};;esac;s="${\
n%${s}*}";((r+=${#s}*(85**(4-i))));};printf -v p "\%03o" $((r>>24)) $((r>>16&255
)) $((r>>8&255)) $((r&255));};for((;(o+${#m})>0;)){ [ "$m" ] || j;while [ "${m:0
:1}" = "z" ];do m=${m:1};printf "\0\0\0\0";done;if [ ${#m} -ge 5 ];then q="${m:0
:5}";m=${m:5};l "$q";printf "$p";elif ((o));then j;elif [ "${m##z*}" ];then pri\
ntf -v t %$((5-${#m}))s;l "$m${t// /u}";printf "${p:0:16-4*${#t}}";m=;fi;}

Copia questo in enc85.she dec85.sh, chmod +x {enc,dec}85.shpoi:

./enc85.sh <<<'Hello world!'
<~87cURD]j7BEbo80$3~>
./dec85.sh <<<'<~87cURD]j7BEbo80$3~>'
Hello world!

Ma potresti fare qualche test più forte:

ls -ltr --color $HOME/* | gzip | ./enc85.sh | ./dec85.sh | gunzip

Ridotto a 724 caratteri:

printf -v n \\%o {32..126};printf -v n "$n";printf -v m %-20sE abtnvfr;p=\<~
l(){ q=$(($1<<24|$2<<16|$3<<8|$4))
q="${n:1+(q/64#378iN)%85:1}${n:1+(q/614125)%85:1}${n:1+(q/7225)%85:1}${n:1+(q/85)%85:1}${n:1+q%85:1}"
};k() { ((${#p}>74))&&echo "${p:0:75}" && p=${p:75};};while IFS= read -rd '' -n 1 q;do [ "$q" ]&&{
printf -v q "%q" "$q";case ${#q} in 1|2)q=${n%$q*};o+=($((${#q}+32)));;7)q=${q#*\'\\}
o+=($((8#${q%\'})));;5)q=${q#*\'\\};q=${m%${q%\'}*};o+=($((${#q}+07)));;esac;}||o+=(0)
((${#o[@]}>3))&&{ [ "${o[*]}" = "0 0 0 0" ]&&q=z||l ${o[@]};p+="${q}";k
o=();};done;[ "$o" ]&&{ f=0;for((;${#o[@]}<4;)){ o+=(0);((f++));}
((f==0))&&[ "${o[*]}" = "0 0 0 0" ]&&q=z||l ${o[@]};p+="${q:0:5-f}";};p+="~>";k;[ "$p" ]&&echo "$p"
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.