Base85 Кодировка

10

Соревнование

Напишите программу, которая может принимать ввод однострочной строки, содержащей любые печатные символы ASCII, и выводить ту же строку, закодированную в Base85 (с использованием соглашения с прямым порядком байтов). Вы можете предположить, что ввод всегда будет ≤ 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 с прямым порядком байтов по ссылке в википедии
Уровень Река
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 или дополнением закодированных фрагментов длиной до 5, поскольку входные данные будут содержать только печатаемые символы ASCII.

Деннис
источник
3
Это решение выглядит подозрительно, как версия ASCII-строки для Base85 (см. Последний рассматриваемый пример). Подождите ...
Ojdo
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 Спасибо! Все это декодирование все еще убивает меня, хотя.
Деннис
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? (Опять же, никогда не занимался гольфом раньше ...)
Дэвид
Добро пожаловать в Программирование Пазлов и Code Golf! Кажется, есть проблема с входными длинами, которые не делятся на 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) '~>'])

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

Я разместил код на 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в Октаве разрешено базирование выше 36?
Луис Мендо
Как сказано в документе (и сообщении об ошибке): аргумент BASEдолжен быть числом от 2 до 36 или строкой символов . Здесь выражение 'i':'u'расширяет строку из 85 символов, !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuкоторая служит основой.
ojdo
@ojdo Если это так, то я должен сделать это функцией и, возможно, сохранить пару байтов.
мензурка
1
@ Beaker Это делает. Не только ограничение 36, но и тот факт, что цифры обязательно равны 0 ... 9ABC, поэтому в кодах ASCII есть скачок
Луис Мендо
1

Matlab, 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"
Ф. Хаури
источник