Base85エンコーディング


10

チャレンジ

ASCII印刷可能文字を含む単一行の文字列の入力を受け取りBase85でエンコードされた同じ文字列を(ビッグエンディアン規則を使用して)出力できるプログラムを記述します。入力は常に100文字以下であると想定できます。


Base85のガイド

  • 4オクテットは、(通常)5つのBase85文字にエンコードされます。

  • Base85文字が範囲!u及び- (117 ASCII 33)z(ASCII 122)。

  • エンコードするには、4オクテット(32ビット数)で85による除算を継続的に実行し、(各除算の後に)残りに33を加算して、エンコードされた値のASCII文字を取得します。たとえば、このプロセスの最初のアプリケーションは、エンコードされたブロックの右端の文字を生成します。

  • 4オクテットのセットにnullバイトのみが含まれる場合、それらはのz代わりにとしてエンコードされ!!!!!ます。

  • 最後のブロックが4オクテットより短い場合は、ヌルバイトが埋め込まれます。エンコード後、パディングとして追加されたのと同じ数の文字が出力の最後から削除されます。

  • エンコードされた値の前後には<~、が必要~>です。

  • エンコードされた値には、空白を含めないでください(このチャレンジのため)。


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ビットのバイトを許可しない理由について、私は混乱しています。
Peter Taylor

エンディアンを指定する必要があります。ブロック[0,1,2,3]は32ビットの数値に0x0123または0x3210?として変換されますか?
edc65 2015

ウィキペディアのリンクによると@ edc65ビッグエンディアン
Level River St

3
@steveverrillありがとうございます。これは、外部リンクではなく、チャレンジテキストに含める必要があります。少なくとも現在はコメントに含まれています
edc65

入力に印刷可能な文字のみを含めることができる場合、4つのnullバイトをどのように含めることができますか?
Luis Mendo 2015

回答:


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
このソリューションは、疑わしいことに、Base85バージョンのASCII文字列に似ています(問題の最後の例を参照)。お待ちください...
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でゴルフをしたことがないので、これはおそらく最適ではありません。

3バイトをオフにしてくれた@ZachGatesに感謝します。


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を使用している場合)。また、関数を呼び出したり、ユーザーの入力を取得したりすることはないため、実行しても何も起こりません。
ザックゲイツ

それが関数である必要があるのか​​、I / Oを読み取る必要があるのか​​わからなかった... stdinを読み取ってstdoutを出力する必要があるのか​​?(繰り返しになりますが、これまでコードゴルフをしたことはありません...)
David

プログラミングパズルとコードゴルフへようこそ!4(最後の2つのテストケース)で割り切れない入力長に問題があるようです。3行目が読み取ら[:4+len(s)/4*4]れ、出力の最後から文字は削除されません。
デニス

私は問題を修正したと思います(残念ながら長くなりました)。さらに最適化しようとしています...
David

2番目のwhileループを次のようなものに変えることができますwhile b:d=chr(b%85+33)+d;b/=85printステートメントと文字列の間のスペースを削除することもできます。さらに、に渡された引数間のスペースを削除しs.unpackます。
ザックゲイツ

2

オクターブ、133 131バイト

stdinではなくargvから入力を取得するよう提案してくれた@ojdoに感謝し、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からの出力例:

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

なぜ使用しないのargv()ですか?タスクの説明では、からの入力を読み取る必要がないようですstdin
ojdo 2015

非常に素晴らしい!それではdec2base、Octave では36を超えるベースを許可しますか?
Luis Mendo 2015

ドキュメント(およびエラーメッセージ)が言うBASEように、引数は2から36までの数値、または記号の文字列でなければなりません。ここでは、ベースと'i':'u'なる85文字の文字列!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuを式で展開しています。
ojdo 2015

@ojdoその場合は、それを関数にして、数バイトを節約する必要があります。
ビーカー

1
@beakerします。36の制限だけでなく、数字は必ず0 ... 9ABCであるという事実により、ASCIIコードにジャンプがあります
Luis Mendo

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

純粋なbash、〜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.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"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.