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"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.