Base85编码


10

挑战

编写一个程序,该程序可以接受包含任何ASCII可打印字符的单行字符串的输入,并输出以Base85编码的相同字符串(使用big-endian约定)。您可以假设输入将始终≤100个字符。


Base85指南

  • 四个八位位组被编码为(通常)五个Base85字符。

  • Base85字符的范围从!u(ASCII 33-117 )和z(ASCII 122)。

  • 要进行编码,您需要对四个八位位组(一个32位数字)连续执行除以85的操作,然后将余数加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根据维基百科链接的大字节序
Level River St

3
@steveverrill谢谢。那应该在挑战文本中,而不是在外部链接中。至少现在在评论中
edc65

如果输入只能包含可打印字符,那么如何包含四个空字节?
路易斯·门多

Answers:


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最初只包含一个字符,所以输出将是正确的。

由于输入将仅包含可打印的ASCII字符,因此我们不必处理z或将编码的块填充到长度5。


3
该解决方案看起来像ASCII字符串的Base85版本(可疑的最后一个示例)。等待...
ojdo

1
@odjo:CJam代码中有一些无效字符,我得到的最接近的是此CJam解释器链接
schnaader

@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)。您也永远不会调用该函数,也不会获取用户的输入,因此在您运行它时,它不会执行任何操作。
扎克·盖茨2015年

不确定是应该使用函数还是读取I / O还是应该读取标准输入并输出标准输出?(再次,以前从未做过代码高尔夫……)
大卫

欢迎来到编程难题和代码高尔夫球!输入长度似乎无法被4整除(最后2个测试用例),这似乎是一个问题。第3行应该读取,[:4+len(s)/4*4]并且不会从输出末尾删除任何字符。
丹尼斯

我相信我已经解决了这些问题(不幸的是延长了时间)。试图优化更多...
大卫

您可以将第二个while循环变成这样的循环:while b:d=chr(b%85+33)+d;b/=85。您还可以删除print语句和字符串之间的空格。此外,删除传递给的参数之间的空格s.unpack
扎克·盖茨

2

八度,133131字节

感谢@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上发布了代码。独立函数不需要and end语句,但是由于ideone在同一文件中具有函数和调用脚本,因此需要分隔符。

我仍然无法弄清楚如何stdin在ideone上工作。如果有人知道,我仍然很感兴趣,所以请给我评论。

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'扩展了!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu用作基础的85字符串。
ojdo

@ojdo如果是这种情况,那么我应该使其成为一个函数,并可能保存几个字节。
烧杯2015年

1
@beaker确实如此。不仅限于36,而且数字必须为0 ... 9ABC,因此ASCII码有了很大的变化
Luis

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.shdec85.shchmod +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"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.