การเข้ารหัส Base85


10

ความท้าทาย

เขียนโปรแกรมที่สามารถรับอินพุตของสตริงบรรทัดเดียวที่มีอักขระที่พิมพ์ได้ใด ๆ ของ ASCII และส่งออกสตริงเดียวกันที่เข้ารหัสในBase85 (โดยใช้การประชุมแบบ big-endian) คุณสามารถสันนิษฐานได้ว่าข้อมูลที่ป้อนจะมีค่า≤ 100 ตัวอักษรเสมอ


คำแนะนำเกี่ยวกับ Base85

  • สี่ octets จะถูกเข้ารหัสเป็น (ปกติ) ห้าตัวอักษร Base85

  • อักขระ Base85 มีตั้งแต่!ถึงu(ASCII 33 - 117) และz(ASCII 122)

  • ในการเข้ารหัสคุณดำเนินการหารอย่างต่อเนื่องโดย 85 ในสี่ octets (หมายเลข 32 บิต) และเพิ่ม 33 ไปยังส่วนที่เหลือ (หลังแต่ละส่วน) เพื่อรับอักขระ ASCII สำหรับค่าที่เข้ารหัส ตัวอย่างเช่นแอปพลิเคชันแรกของกระบวนการนี้สร้างอักขระที่ถูกต้องที่สุดในบล็อกที่เข้ารหัส

  • ถ้าชุดของสี่ octets มีเพียงไบต์ null พวกเขาจะถูกเข้ารหัสเป็นแทน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 ที่พิมพ์ได้จากนั้นคุณใช้ไบต์เป็นคำพ้องความหมายของoctetและไม่อนุญาตให้ใช้ไบต์ 7 บิต
Peter Taylor

ควรระบุ Endianness บล็อก [0,1,2,3] ถูกแปลงเป็นตัวเลข 32 บิตเป็น 0x0123 หรือ 0x3210?
edc65

@ edc65 big endian ตามลิงก์วิกิพีเดีย
Level River St

3
@ สตีฟเวอร์ริลล์ขอบคุณ ควรอยู่ในข้อความท้าทายไม่ใช่ลิงก์ภายนอก อย่างน้อยก็อยู่ในความคิดเห็นตอนนี้
edc65

หากอินพุตมีได้เฉพาะอักขระที่พิมพ์ได้วิธีนั้นจะมีสี่ไบต์ว่างได้อย่างไร
Luis Mendo

คำตอบ:


9

CJam, 43 39 35 bytes

"<~"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
วิธีการแก้ปัญหานี้ดูน่าสงสัยเหมือนกับรุ่น 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 ดังนั้นนี่น่าจะเหมาะสมที่สุด

ขอบคุณ @ZachGates สำหรับการเล่นกอล์ฟ 3 ไบท์!


1
คุณสามารถใช้input().encode()แทนstr.encode(input())การบันทึก 3 ไบต์
Zach Gates

@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) คุณไม่เคยเรียกใช้ฟังก์ชันหรือรับอินพุตของผู้ใช้ดังนั้นจึงไม่ทำอะไรเลยเมื่อคุณเรียกใช้
Zach Gates

ไม่แน่ใจว่ามันควรจะเป็นฟังก์ชั่นหรืออ่าน I / O หรืออะไร ... มันควรจะอ่าน stdin และพิมพ์ stdout? (อีกครั้งไม่เคยเล่นรหัสกอล์ฟมาก่อน ... )
David

ยินดีต้อนรับสู่ Programming Puzzles & Code Golf! ดูเหมือนว่าจะมีปัญหากับความยาวอินพุตที่ไม่หารด้วย 4 (กรณีทดสอบ 2 ครั้งล่าสุด) ควรอ่านบรรทัดที่ 3 [:4+len(s)/4*4]และไม่มีตัวอักษรใดถูกลบออกจากส่วนท้ายของเอาต์พุต
เดนนิส

ฉันเชื่อว่าฉันแก้ไขปัญหาได้แล้ว พยายามเพิ่มประสิทธิภาพให้มากขึ้น ...
David

คุณสามารถเปิดที่สองของคุณห่วงเป็นหนึ่งเหมือนเช่นนี้while while b:d=chr(b%85+33)+d;b/=85นอกจากนี้คุณยังสามารถลบช่องว่างระหว่างprintคำสั่งของคุณและสตริง s.unpackนอกจากนี้ลบช่องว่างระหว่างการขัดแย้งผ่านไป
Zach Gates

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 หากใครรู้ฉันยังคงสนใจดังนั้นโปรดส่งความคิดเห็นมาให้ฉัน

ตัวอย่างผลลัพธ์จากideone :

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

ทำไมไม่ใช้เพียงargv()? stdinรายละเอียดงานที่ดูเหมือนจะไม่จำเป็นต้องมีการอ่านข้อมูลจาก
ojdo

ดีมาก! ดังนั้นdec2baseใน Octave อนุญาตให้มีฐานที่สูงกว่า 36 หรือไม่?
Luis Mendo

ในฐานะที่เป็น doc (และข้อผิดพลาด) กล่าวว่า: อาร์กิวเมนต์BASEต้องเป็นตัวเลขระหว่าง 2 และ 36, หรือสตริงสัญลักษณ์ ในที่นี้นิพจน์'i':'u'จะขยายสตริงอักขระ 85 ตัว!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuที่ทำหน้าที่เป็นฐาน
ojdo

@ojdo หากเป็นกรณีนี้ฉันควรทำให้เป็นฟังก์ชันและอาจบันทึกสองไบต์
บีกเกอร์

1
@ คนทำมันทำ ไม่เพียง แต่ จำกัด ไว้ที่ 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

ทุบตีบริสุทธิ์ ~ 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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.