Mã hóa Base85


10

Các thách thức

Viết chương trình có thể lấy đầu vào của một chuỗi đơn có chứa bất kỳ ký tự có thể in ASCII nào và xuất ra cùng một chuỗi được mã hóa trong Base85 (sử dụng quy ước lớn về cuối). Bạn có thể giả sử rằng đầu vào sẽ luôn là 100 ký tự.


Hướng dẫn về Base85

  • Bốn octet được mã hóa thành (thường) năm ký tự Base85.

  • Các ký tự Base85 có phạm vi từ !đến u(ASCII 33 - 117) và z(ASCII 122).

  • Để mã hóa, bạn liên tục thực hiện phép chia cho 85 trên bốn octet (số 32 bit) và thêm 33 vào phần còn lại (sau mỗi phép chia) để lấy ký tự ASCII cho giá trị được mã hóa. Ví dụ, ứng dụng đầu tiên của quy trình này tạo ra ký tự ngoài cùng bên phải trong khối được mã hóa.

  • Nếu một bộ bốn octet chỉ chứa byte rỗng, chúng được mã hóa zthay vì !!!!!.

  • Nếu khối cuối cùng ngắn hơn bốn octet, thì nó được đệm bằng các byte rỗng. Sau khi mã hóa, cùng một số ký tự được thêm vào dưới dạng phần đệm, sẽ bị xóa khỏi phần cuối của đầu ra.

  • Giá trị được mã hóa phải được đi trước <~và theo sau ~>.

  • Giá trị được mã hóa không được chứa khoảng trắng (đối với thử thách này).


Ví dụ

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~>

Đoạn mã sau sẽ mã hóa một đầu vào đã cho thành Base85.


3
Tôi bối rối không hiểu tại sao, do bạn giới hạn đầu vào ở dạng ASCII có thể in được, sau đó bạn sử dụng byte làm từ đồng nghĩa của octet và không cho phép byte 7 bit.
Peter Taylor

Endianness nên được chỉ định. Một khối [0,1,2,3] được chuyển đổi thành số 32 bit là 0x0123 hoặc 0x3210?
edc65

@ edc65 endian lớn theo liên kết wikipedia
Level River St

3
@steveverrill cảm ơn bạn. Điều đó nên có trong văn bản thách thức, và không phải trong một liên kết bên ngoài. Ít nhất đó là trong một bình luận bây giờ
edc65

Nếu đầu vào chỉ có thể chứa các ký tự có thể in được, làm thế nào nó có thể chứa bốn byte null?
Luis Mendo

Câu trả lời:


9

CJam, 43 39 35 byte

"<~"q4/{:N4Ue]256b85b'!f+}/N,)<"~>"

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

"<~"      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ếu đầu vào trống, N,)sẽ áp dụng cho chuỗi "<~". Vì Nban đầu giữ một ký tự duy nhất, đầu ra sẽ chính xác.

Chúng ta không phải đối phó với z hoặc đệm các đoạn được mã hóa đến độ dài 5, vì đầu vào sẽ chỉ chứa các ký tự ASCII có thể in được.


3
Giải pháp này trông đáng ngờ giống như phiên bản Base85 của chuỗi ASCII (xem ví dụ cuối cùng trong câu hỏi). Đợi ...
ojdo

1
@odjo: Có một số ký tự không hợp lệ trong mã CJam, gần nhất tôi nhận được là liên kết trình thông dịch CJam này
schnaader

@ojdo vì thử thách chỉ là thế này:a program that can take an input of a single-line string containing any ASCII printable characters,...
edc65

5

Python 3, 71 byte

from base64 import*
print(a85encode(input().encode(),adobe=1).decode())

Tôi chưa bao giờ chơi gôn trong Python, vì vậy đây có thể là tối ưu.

Cảm ơn @ZachGates vì ​​đã chơi golf 3 byte!


1
Bạn có thể sử dụng input().encode()thay vì str.encode(input())để lưu 3 byte.
Zach Gates

@ZachGates Cảm ơn! Tất cả những gì en- / giải mã vẫn đang giết chết tôi.
Dennis

2

Python 2, 193 162 byte

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]

Đây là môn đánh gôn đầu tiên của tôi, vì vậy tôi chắc chắn có điều gì đó không đúng với cách tiếp cận của tôi. Tôi cũng muốn thực sự triển khai base85 thay vì chỉ gọi hàm thư viện. :)


Đây là 181 byte. Đừng quên xóa dòng mới mà IDLE thêm vào mã của bạn khi bạn lưu (nếu bạn đang sử dụng IDLE). Bạn cũng không bao giờ gọi hàm hoặc nhận đầu vào của người dùng, vì vậy nó không làm gì khi bạn chạy nó.
Zach Gates

Không chắc nó có phải là một hàm hay đọc I / O hay không ... nó có nên đọc stdin và in stdout không? (Một lần nữa, không bao giờ thực hiện mã golf trước đó ...)
David

Chào mừng bạn đến với Câu đố lập trình & Code Golf! Dường như có một vấn đề với độ dài đầu vào không chia hết cho 4 (2 trường hợp kiểm tra gần nhất). Dòng 3 nên đọc [:4+len(s)/4*4]và không có ký tự nào bị xóa khỏi cuối đầu ra.
Dennis

Tôi tin rằng tôi đã sửa các vấn đề (và không may làm cho nó dài hơn). Đang cố gắng tối ưu hóa nhiều hơn ...
David

Bạn có thể biến whilevòng lặp thứ hai của mình thành một vòng như thế này : while b:d=chr(b%85+33)+d;b/=85. Bạn cũng có thể xóa khoảng trắng giữa printcâu lệnh của bạn và chuỗi. Ngoài ra, loại bỏ khoảng trắng giữa các đối số được truyền vào s.unpack.
Zach Gates

2

Octave, 133 131 byte

Cảm ơn @ojdo đã gợi ý tôi lấy đầu vào từ argv chứ không phải stdin, tiết kiệm cho tôi 2 byte.

function g(s) p=mod(-numel(s),4);s(end+1:end+p)=0;disp(['<~' dec2base(swapbytes(typecast(s,'uint32')),'!':'u')'(:)'(1:end-p) '~>'])

Ung dung:

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

Tôi đã đăng mã trên ideone . Hàm độc lập không yêu cầu và endtuyên bố, nhưng vì ideone có chức năng và tập lệnh gọi trong cùng một tệp nên nó yêu cầu một dấu phân cách.

Tôi vẫn chưa thể tìm ra cách stdinđể làm việc trên ideone. Nếu ai biết, tôi vẫn quan tâm, vì vậy xin vui lòng gửi cho tôi một nhận xét.

Đầu ra mẫu từ ideone :

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

Tại sao không chỉ sử dụng argv()? Mô tả nhiệm vụ dường như không yêu cầu đọc đầu vào từ stdin.
ojdo

Rất đẹp! Vì vậy, dec2basetrong Octave cho phép các căn cứ trên 36?
Luis Mendo

Như tài liệu (và thông báo lỗi) nói: đối số BASEphải là một số từ 2 đến 36 hoặc một chuỗi các ký hiệu . Ở đây, biểu thức 'i':'u'mở rộng chuỗi 85 ký tự !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuđóng vai trò là cơ sở.
ojdo

@ojdo Nếu đó là trường hợp thì tôi nên biến nó thành một hàm và có thể tiết kiệm một vài byte.
cốc

1
@beaker Nó làm. Không chỉ giới hạn ở 36, mà thực tế là các chữ số nhất thiết phải là 0 ... 9ABC, do đó, có một bước nhảy trong mã ASCII
Luis Mendo

1

Matlab, 175 byte

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) '~>']

Thí dụ:

>> 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 byte

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~>";

Phiên bản trực tuyến

Mở rộng

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 tinh khiết, ~ 738

Bộ mã hóa đầu tiên (một cái gì đó được đánh gôn):

#!/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"

Các xét nghiệm:

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~>

và bộ giải mã ngay bây giờ:

#!/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;}

Sao chép này trong enc85.shdec85.sh, chmod +x {enc,dec}85.shthì:

./enc85.sh <<<'Hello world!'
<~87cURD]j7BEbo80$3~>
./dec85.sh <<<'<~87cURD]j7BEbo80$3~>'
Hello world!

Nhưng bạn có thể làm một số bài kiểm tra mạnh mẽ hơn:

ls -ltr --color $HOME/* | gzip | ./enc85.sh | ./dec85.sh | gunzip

Giảm xuống 724 ký tự:

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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.