Кодування Base85


10

Змагання

Напишіть програму, яка може приймати введення однорядкового рядка, що містить будь-які символи для друку ASCII, та виводить ту саму рядок, закодовану в Base85 (використовуючи конвенцію big-endian). Можна припустити, що вхід завжди буде ≤ 100 символів.


Посібник по Base85

  • Чотири октети закодовані в (зазвичай) п'ять символів Base85.

  • Base85 символи в діапазоні від !до u(ASCII 33 - 117) і z(122) ASCII.

  • Для кодування ви постійно виконуєте ділення на 85 на чотири октети (32-бітове число) і додаєте 33 до решти (після кожного поділу), щоб отримати символ ASCII для кодованого значення. Наприклад, перше застосування цього процесу виробляє найправіший символ у кодованому блоці.

  • Якщо набір з чотирьох октетів містить лише нульові байти, вони кодуються як zзамість !!!!!.

  • Якщо останній блок коротший чотирьох октетів, він оброблений нульовими байтами. Після кодування з кінця виводу видаляється та сама кількість символів, яка була додана як підкладка.

  • Кодованому значенню слід передувати <~та супроводжувати його ~>.

  • Кодоване значення не повинно містити пробілів (для цього виклику).


Приклади

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~>

Наступний фрагмент кодує заданий вхід до Base85.


3
Мене бентежить, чому, враховуючи, що ви обмежуєте вхід для друку ASCII, ви використовуєте байт як синонім октету і не допускаєте 7-бітових байтів.
Пітер Тейлор

Необхідно вказати ендіанси. Блок [0,1,2,3] перетворюється в 32-бітове число як 0x0123 або 0x3210?
edc65

@ edc65 big endian за посиланням на wikipedia
Level River St

3
@steveverrill дякую Це має бути у тексті виклику, а не у зовнішньому посиланні. Принаймні, це в коментарі зараз
edc65

Якщо вхід може містити лише символи для друку, як він може містити чотири нульові байти?
Луїс Мендо

Відповіді:


9

CJam, 43 39 35 байт

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

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

"<~"      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.

Якщо введення було порожнім, N,)буде застосовано до рядка "<~". Оскільки Nспочатку міститься один символ, вихід буде правильним.

Нам не доводиться мати справу з z або pad кодованих фрагментів довжиною 5, оскільки вхід буде містити лише друковані символи ASCII.


3
Це рішення підозріло виглядає як версія Base85 рядка ASCII (див. Останній приклад, про який йдеться). Зачекайте ...
ойдо

1
@odjo: У коді CJam є кілька недійсних символів, найближче мені це посилання для перекладача
CJam

@ojdo тому, що виклик якраз такий:a program that can take an input of a single-line string containing any ASCII printable characters,...
edc65

5

Python 3, 71 байт

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

Я ніколи не займався гольфуванням в Python, тому це, мабуть, недостатньо оптимально.

Дякуємо @ZachGates за те, що ти граєш на 3 байти!


1
Ви можете використовувати input().encode()замість того, str.encode(input())щоб зберегти 3 байти.
Зак Гейтс

@ZachGates Дякую! Все, що en / / декодування все ще вбиває мене.
Денніс

2

Python 2, 193 162 байт

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]

Це мій перший гольф з кодом, тому я впевнений, що в моєму підході щось не так. Я також хотів реально реалізувати base85, а не просто викликати функцію бібліотеки. :)


Це 181 байт. Не забудьте видалити новий рядок, який IDLE додає до вашого коду під час збереження (якщо ви використовуєте IDLE). Ви також ніколи не викликаєте функцію або не отримуєте введення користувача, тому вона не робить нічого під час її запуску.
Зак Гейтс

Не був впевнений, чи має це бути функція чи читати введення / вивід чи що ... чи слід читати stdin та друкувати stdout? (Знову ж , ніколи не робив код гольф раніше ...)
David

Ласкаво просимо до головоломки програмування та коду для гольфу! Здається, існує проблема з довжиною введення, яка не ділиться на 4 (останні 2 тестових випадки). У рядку 3 слід читати, [:4+len(s)/4*4]а символи не видаляються з кінця виводу.
Денніс

Я вважаю, що виправили проблеми (і, на жаль, зробили це довше). Намагаючись оптимізувати більше ...
Девід

Ви можете перетворити ваш другий whileцикл в один , як наприклад: while b:d=chr(b%85+33)+d;b/=85. Ви також можете видалити пробіл між вашим printоператором та рядком. Додатково видаліть пробіл між переданими аргументами s.unpack.
Зак Гейтс

2

Октава, 133 131 байт

Завдяки @ojdo за те, що він запропонував мені взяти вклад із argv, а не stdin, заощадивши мені 2 байти.

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

Безголівки:

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

Я розмістив код на ideone . Автономна функція не вимагає і endзаявляти, але оскільки ideone має функцію та виклик сценарію в одному файлі, йому потрібен роздільник.

Я досі не зміг зрозуміти, як stdinвзятись на роботу над ideone. Якщо хтось знає, я все ще зацікавлений, тому, будь ласка, киньте мені коментар.

Вибірка з ідеону :

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

Чому б просто не використовувати argv()? Опис завдання, схоже, не потребує введення читання з stdin.
ojdo

Дуже хороший! Так dec2baseв Octave допускаються бази вище 36?
Луїс Мендо

Як кажуть док (і повідомлення про помилку): аргументом BASEповинно бути число від 2 до 36 або рядок символів . Тут вираз 'i':'u'розширює рядок 85 символів, !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuякий служить базою.
ojdo

@ojdo Якщо це так, я повинен зробити його функцією і, можливо, зберегти пару байтів.
мензурка

1
@beaker Це так. Не тільки обмеження на 36, але й те, що цифри обов'язково 0 ... 9ABC, тому є стрибок у кодах ASCII
Луїс Мендо

1

Матлаб, 175 байт

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) '~>']

Приклад:

>> 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 байт

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~>";

Інтернет-версія

Розширено

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

Чистий баш, ~ 738

Перший кодер (щось із гольфу):

#!/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"

Тести:

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~>

і декодер зараз:

#!/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;}

Скопіюйте це enc85.shі dec85.sh, chmod +x {enc,dec}85.sh, то:

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

Але ви могли б зробити більш сильний тест:

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

Зменшено до 724 знаків:

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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.