Chuyển đổi một mảng byte thành base64


10

Nhiệm vụ của bạn là viết một hàm / chương trình chuyển đổi một mảng byte (nghĩa là: một mảng các số nguyên từ 0 đến 255), thành base64.

Không được phép sử dụng bộ mã hóa base64 tích hợp.

Việc triển khai Base64 được yêu cầu là RFC 2045. (sử dụng "+", "/" và phần đệm bắt buộc với "=")

Mã ngắn nhất (tính bằng byte) sẽ thắng!

Thí dụ:

Đầu vào (mảng int): [99, 97, 102, 195, 169]

Đầu ra (chuỗi): Y2Fmw6k=


Đây là loại cạnh tranh nào?
Cilan

Có phải bộ mã hóa base64 tích hợp chỉ bao gồm bộ mã hóa nhị phân thành văn bản hoặc các hàm thao tác với số nguyên không?
Dennis

1
Để làm rõ: Tôi có thể sử dụng hàm trả về 1 2cho đối số 66không?
Dennis

1
9 phiên bản tiêu chuẩn hóa hoặc 4 phiên bản không chuẩn của Base64. Tài liệu tham khảo của bạn =cho phần đệm thu hẹp nó xuống còn 4. Bạn muốn cái nào? Hay bạn muốn một biến thể không chuẩn không có độ dài dòng tối đa?
Peter Taylor

Tôi đoán anh ấy / cô ấy đã đề cập đến "tiêu chuẩn" được chỉ định bởi RFC 4648 hoặc phiên bản được sử dụng bởi các loại MIME, RFC 2045. Đây là những cách khác nhau, vì vậy việc làm rõ sẽ rất hữu ích.
bán bên ngoài

Câu trả lời:


3

Lắp ráp x86 32 bit, 59 byte

Mã byte:

66 B8 0D 0A 66 AB 6A 14 5A 4A 74 F4 AD 4E 45 0F C8 6A 04 59 C1 C0 06 24 3F 3C 3E 72 05 C0
E0 02 2C 0E 2C 04 3C 30 7D 08 04 45 3C 5A 76 02 04 06 AA 4D E0 E0 75 D3 B0 3D F3 AA C3

Tháo gỡ:

b64_newline:
    mov     ax, 0a0dh
    stosw
b64encode:
    push    (76 shr 2) + 1
    pop     edx
b64_outer:
    dec     edx
    je      b64_newline
    lodsd
    dec     esi
    inc     ebp
    bswap   eax
    push    4
    pop     ecx
b64_inner:
    rol     eax, 6
    and     al, 3fh
    cmp     al, 3eh
    jb      b64_testchar
    shl     al, 2     ;'+' and '/' differ by only 1 bit
    sub     al, ((3eh shl 2) + 'A' - '+') and 0ffh
b64_testchar:
    sub     al, 4
    cmp     al, '0'
    jnl     b64_store ;l not b because '/' is still < 0 here
    add     al, 'A' + 4
    cmp     al, 'Z'
    jbe     b64_store
    add     al, 'a' - 'Z' - 1
b64_store:
    stosb
    dec     ebp
    loopne  b64_inner
    jne     b64_outer
    mov     al, '='
    rep     stosb
    ret

Gọi b64encode với esi trỏ đến bộ đệm đầu vào, edi trỏ đến bộ đệm đầu ra.

Nó có thể được làm nhỏ hơn nữa nếu gói không được sử dụng.


3

JavaScript, 177 187 198 nhân vật

function(d){c="";for(a=e=b=0;a<4*d.length/3;f=b>>2*(++a&3)&63,c+=String.fromCharCode(f+71-(f<26?6:f<52?0:f<62?75:f^63?90:87)))a&3^3&&(b=b<<8^d[e++]);for(;a++&3;)c+="=";return c}

Để thêm ngắt dòng, \r\nsau mỗi ký tự thứ 76, thêm 23 ký tự vào mã:

function(d){c="";for(a=e=b=0;a<4*d.length/3;f=b>>2*(++a&3)&63,c+=String.fromCharCode(f+71-(f<26?6:f<52?0:f<62?75:f^63?90:87))+(75==(a-1)%76?"\r\n":""))a&3^3&&(b=b<<8^d[e++]);for(;a++&3;)c+="=";return c}

Mã trình diễn:

var encode = function(d,a,e,b,c,f){c="";for(a=e=b=0;a<4*d.length/3;f=b>>2*(++a&3)&63,c+=String.fromCharCode(f+71-(f<26?6:f<52?0:f<62?75:f^63?90:87))+(75==(a-1)%76?"\r\n":""))a&3^3&&(b=b<<8^d[e++]);for(;a++&3;)c+="=";return c};

//OP test case
console.log(encode([99, 97, 102, 195, 169])); // outputs "Y2Fmw6k=".

//Quote from Hobbes' Leviathan:
console.log(
 encode(
  ("Man is distinguished, not only by his reason, but by this singular passion from " +
   "other animals, which is a lust of the mind, that by a perseverance of delight " +
   "in the continued and indefatigable generation of knowledge, exceeds the short " +
   "vehemence of any carnal pleasure.")
  .split('').map(function(i){return i.charCodeAt(0)})
 )
);


Giải pháp tốt đẹp! Bạn có thể tắt một số byte bằng một số tính năng ES6 và xóa một số sao chép: Mã rút ngắn với các nhận xét
Craig Ayre

@CraigAyre, cảm ơn vì đầu vào mang tính xây dựng. ES6 đã không được hoàn thiện và có sẵn tại thời điểm thử thách này ban đầu được đăng. Theo đề xuất tại codegolf.meta , bạn có thể đăng phiên bản ES6 rút gọn và đánh dấu nó là không cạnh tranh.
Tomas Langkaas

Đừng lo lắng, lỗi của tôi vì đã không kiểm tra lại ngày đăng bài gốc! Tôi là một fan hâm mộ của giải pháp của bạn vì vậy tôi sẽ không đăng bài khác, nhưng cảm ơn vì liên kết. Logic theo nghĩa đen của mẫu đã loại bỏ trùng lặp bảng chữ cái có thể được chuyển đổi thành ES5 trong cùng một số byte, không tiết kiệm được nhiều nhưng mỗi lần đếm nhỏ!
Craig Ayre

@CraigAyre, một lần nữa cảm ơn vì tiền boa, đã tìm ra một cách khác để nén các ký hiệu base64 hơn nữa (điều này làm cho nó thậm chí còn tương thích ngược hơn - giờ cũng sẽ hoạt động trong IE cũ).
Tomas Langkaas

1

perl, 126 byte

đọc stdin, xuất ra stdout

$/=$\;print map{$l=y///c/2%3;[A..Z,a..z,0..9,"+","/"]->[oct"0b".substr$_.0 x4,0,6],$l?"="x(3-$l):""}unpack("B*",<>)=~/.{1,6}/g

vô dụng:

my @x = ('A'..'Z','a'..'z',0..9,'+','/');
my $in = join '', <>;
my $bits = unpack 'B*', $in;
my @six_bit_groups = $bits =~ /.{1,6}/g;
for my $sixbits (@six_bit_groups) {
  next unless defined $sixbits;
  $l=length($sixbits)/2%3;
  my $zero_padded = $sixbits . ( "0" x 4 );
  my $padded_bits = substr( $zero_padded, 0, 6 );
  my $six_bit_int = oct "0b" . $padded_bits;
  print $x[$six_bit_int];
  print "=" x (3 - $l)  if  $l;
}

Câu hỏi đã được làm rõ để yêu cầu RFC 2045, vì vậy bạn cần thêm một chút mã để phân chia đầu ra thành các khối 76 char và tham gia với \r\n.
Peter Taylor

1

Perl, 147 byte

sub b{$f=(3-($#_+1)%3)%3;$_=unpack'B*',pack'C*',@_;@r=map{(A..Z,a..z,0..9,'+','/')[oct"0b$_"]}/.{1,6}/g;$"='';join"\r\n",("@r".'='x$f)=~/.{1,76}/g}

Hàm lấy danh sách các số nguyên làm đầu vào và đầu ra chuỗi, mã hóa base64.

Thí dụ:

print b(99, 97, 102, 195, 169)

in

Y2Fmw6kA

Ung dung:

Phiên bản cũng trực quan hóa các bước trung gian:

sub b {
    # input array: @_
    # number of elements: $#_ + 1 ($#_ is zero-based index of last element in 
    $fillbytes = (3 - ($#_ + 1) % 3) % 3;
      # calculate the number for the needed fill bytes
      print "fillbytes:       $fillbytes\n";
    $byte_string = pack 'C*', @_;
      # the numbers are packed as octets to a binary string
      # (binary string not printed)
    $bit_string = unpack 'B*', $byte_string;
      # the binary string is converted to its bit representation, a string wit
      print "bit string:      \"$bit_string\"\n";
    @six_bit_strings = $bit_string =~ /.{1,6}/g;
      # group in blocks of 6 bit
      print "6-bit strings:   [@six_bit_strings]\n";
    @index_positions = map { oct"0b$_" } @six_bit_strings;
      # convert bit string to number
      print "index positions: [@index_positions]\n";
    @alphabet = (A..Z,a..z,0..9,'+','/');
      # the alphabet for base64
    @output_chars = map { $alphabet[$_] } @index_positions;
      # output characters with wrong last characters that entirely derived fro
      print "output chars:    [@output_chars]\n";
    local $" = ''; #"
    $output_string = "@output_chars";
      # array to string without space between elements ($")
      print "output string:   \"$output_string\"\n";
    $result = $output_string .= '=' x $fillbytes;
      # add padding with trailing '=' characters
      print "result:          \"$result\"\n";
    $formatted_result = join "\r\n", $result =~ /.{1,76}/g;
      # maximum line length is 76 and line ends are "\r\n" according to RFC 2045
      print "formatted result:\n$formatted_result\n";
    return $formatted_result;
}

Đầu ra:

fillbytes:       1
bit string:      "0110001101100001011001101100001110101001"
6-bit strings:   [011000 110110 000101 100110 110000 111010 1001]
index positions: [24 54 5 38 48 58 9]
output chars:    [Y 2 F m w 6 J]
output string:   "Y2Fmw6J"
result:          "Y2Fmw6J="
formatted result:
Y2Fmw6J=

Các xét nghiệm:

Các chuỗi kiểm tra đến từ ví dụ trong câu hỏi các ví dụ trong bài viết Wikipedia cho Base64 .

sub b{$f=(3-($#_+1)%3)%3;$_=unpack'B*',pack'C*',@_;@r=map{(A..Z,a..z,0..9,'+','/')[oct"0b$_"]}/.{1,6}/g;$"='';join"\r\n",("@r".'='x$f)=~/.{1,76}/g}

sub test ($) {
   print b(map {ord($_)} $_[0] =~ /./sg), "\n\n";
}

my $str = <<'END_STR';
Man is distinguished, not only by his reason, but by this singular passion from
other animals, which is a lust of the mind, that by a perseverance of delight
in the continued and indefatigable generation of knowledge, exceeds the short
vehemence of any carnal pleasure.
END_STR
chomp $str;

test "\143\141\146\303\251";
test $str;
test "any carnal pleasure.";
test "any carnal pleasure";
test "any carnal pleasur";
test "any carnal pleasu";
test "any carnal pleas";
test "pleasure.";
test "leasure.";
test "easure.";
test "asure.";
test "sure.";

Đầu ra thử nghiệm:

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZSO=

YW55IGNhcm5hbCBwbGVhc3VyZSO=

YW55IGNhcm5hbCBwbGVhc3VyZB==

YW55IGNhcm5hbCBwbGVhc3Vy

YW55IGNhcm5hbCBwbGVhc3F=

YW55IGNhcm5hbCBwbGVhcD==

cGxlYXN1cmUu

bGVhc3VyZSO=

ZWFzdXJlLC==

YXN1cmUu

c3VyZSO=

Câu hỏi đã được làm rõ để yêu cầu RFC 2045, vì vậy bạn cần thêm một chút mã để phân chia đầu ra thành các khối 76 char và tham gia với \r\n.
Peter Taylor

@PeterTaylor: Cảm ơn, tôi đã cập nhật câu trả lời cho RFC 2045.
Heiko Oberdiek

bravo cho câu trả lời rất đầy đủ này. Bao gồm ngắt dòng bắt buộc (bằng cách chỉ định "RFC 2045" trong OP) thực sự là một lỗi, trên thực tế bạn có thể bỏ qua phần đó. Xin lỗi :)
xem

1

Python, 234 ký tự

def F(s):
 R=range;A=R(65,91)+R(97,123)+R(48,58)+[43,47];n=len(s);s+=[0,0];r='';i=0
 while i<n:
  if i%57<1:r+='\r\n'
  for j in R(4):r+=chr(A[s[i]*65536+s[i+1]*256+s[i+2]>>18-6*j&63])
  i+=3
 k=-n%3
 if k:r=r[:-k]+'='*k
 return r[2:]

Câu hỏi đã được làm rõ để yêu cầu RFC 2045, vì vậy bạn cần thêm một chút mã để phân chia đầu ra thành các khối 76 char và tham gia với \r\n.
Peter Taylor

@PeterTaylor: đã sửa.
Keith Randall

1

GolfScript, 80 (77) byte

~.,~)3%:P[0]*+[4]3*\+256base 64base{'+/''A[a{:0'{,^}/=}/{;}P*'='P*]4>76/"\r
":n*

Ở trên sẽ phù hợp với chính xác 76 ký tự trong một dòng, ngoại trừ dòng cuối cùng. Tất cả các dòng được chấm dứt bởi CRLF.

Lưu ý rằng RFC 2045 chỉ định một biến, độ dài dòng tối đa là 76 ký tự, vì vậy với chi phí đầu ra khá, chúng ta có thể tiết kiệm thêm 3 byte.

~.,~)3%:P[0]*+[4]3*\+256base 64base{'+/''A[a{:0'{,^}/=}/{;}P*'='P*]4>{13]n+}/

Ở trên sẽ in một ký tự trên mỗi dòng, ngoại trừ dòng cuối cùng, có thể chứa 0, 1 hoặc 2 =ký tự. GolfScript cũng sẽ nối thêm một bản cuối cùng, theo RFC 2045, phải được bỏ qua bởi phần mềm giải mã.

Thí dụ

$ echo '[99 97 102 195 169]' | golfscript base64.gs | cat -A
Y2Fmw6k=^M$
$ echo [ {0..142} ] | golfscript base64.gs | cat -A
AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4^M$
OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bx^M$
cnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY4=^M$
$ echo '[99 97 102 195 169]' | golfscript base64-sneaky.gs | cat -A
Y^M$
2^M$
F^M$
m^M$
w^M$
6^M$
k^M$
=^M$
$

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

~          # Interpret the input string.
.,~)3%:P   # Calculate the number of bytes missing to yield a multiple of 3 and save in “P”.
[0]*+      # Append that many zero bytes to the input array.
[4]3*\+    # Prepend 3 bytes to the input array to avoid issues with leading zeros.
256base    # Convert the input array into an integer.
64base     # Convert that integer to base 64.
{          # For each digit:
  '+/'     # Push '+/'.
  'A[a{:0' # Push 'A[a{:0'.
  {        # For each byte in 'A[a{:0':
    ,      # Push the array of all bytes up to that byte.
    ^      # Take the symmetric difference with the array below it.
  }/       # Result: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  =        # Retrieve the character corresponding to the digit.
}/         #
{;}P*'='P* # Replace the last “P” characters with a string containing that many “=” chars.
]          # Collect all bytes on the stack into an array.
4>         # Remove the first four, which correspond to the 3 prepended bytes.
76/        # Collect all bytes on the stack into an array and split into 76-byte chunks.
"\r\n":n*  # Join the chunks with separator CRLF and save CRLF as the new line terminator.

1

PHP , 200 byte

<?foreach($g=$_GET as$k=>$v)$b[$k/3^0]+=256**(2-$k%3)*$v;for(;$i<62;)$s.=chr($i%26+[65,97,48][$i++/26]);foreach($b as$k=>$v)for($i=4;$i--;$p++)$r.=("$s+/=")[count($g)*4/3<$p?64:($v/64**$i)%64];echo$r;

Hãy thử trực tuyến!

Bạn có thể thay thế chuỗi ("$s+/=")bằng một mảngarray_merge(range(A,Z),range(a,z),range(0,9),["+","/","="])

Chỉ để so sánh số byte nào có thể đạt được với một tích hợp không được phép

PHP , 45 byte

<?=base64_encode(join(array_map(chr,$_GET)));

Hãy thử trực tuyến!


0

JavaScript (ES6), 220B

f=a=>{for(s=a.map(e=>('0000000'+e.toString(2)).slice(-8)).join(p='');s.length%6;p+='=')s+='00';return s.match(/.{6}/g).map(e=>'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[parseInt(e,2)]).join('')+p}

Nếu trình duyệt của bạn không hỗ trợ ES6, bạn có thể thử với phiên bản này (262B):

function f(a){for(s=a.map(function(e){return ('0000000'+e.toString(2)).slice(-8)}).join(p='');s.length%6;p+='=')s+='00';return s.match(/.{6}/g).map(function(e){return 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[parseInt(e,2)]}).join('')+p}

f([99, 97, 102, 195, 169])trả lại "Y2Fmw6k=".


Mã để chia nó thành các khối 76 char được nối với ở \r\nđâu?
Peter Taylor

0

Con trăn - 310, 333

def e(b):
  l=len;c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";r=p="";d=l(b)%3
  if d>0:d=abs(d-3);p+="="*d;b+=[0]*d
  for i in range(0,l(b)-1,3):
    if l(r)%76==0:r+="\r\n"
    n=(b[i]<<16)+(b[i+1]<<8)+b[i+2];x=(n>>18)&63,(n>>12)&63,(n>>6)&63,n&63;r+=c[x[0]]+c[x[1]]+c[x[2]]+c[x[3]]
  return r[:l(r)-l(p)]+p

Hơi vô dụng:

def e( b ):
    c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    r = p = ""
    d = len( b ) % 3

    if d > 0:
        d = abs( d - 3 )
        p = "=" * d
        b + = [0] * d

    for i in range( 0, len( b ) - 1, 3 ):
        if len( r ) % 76 == 0:
            r += "\r\n"

        n = ( b[i] << 16 ) + ( b[i + 1] << 8 ) + b[i + 2]
        x = ( n >> 18 ) & 63, ( n >> 12 ) & 63, ( n >> 6) & 63, n & 63
        r += c[x[0]] + c[x[1]] + c[x[2]] + c[x[3]]

    return r[:len( r ) - len( p )] + p

Ví dụ :

Mô-đun cơ sở tích hợp sẵn của Python chỉ được sử dụng trong ví dụ này để đảm bảo ehàm có đầu ra chính xác, ebản thân hàm không sử dụng nó.

from base64 import encodestring as enc

test = [ 99, 97, 102, 195, 169 ]
str  = "".join( chr( x ) for x in test )

control = enc( str ).strip()
output = e( test )

print output            # => Y2Fmw6k=
print control == output # => True

Câu hỏi đã được làm rõ để yêu cầu RFC 2045, vì vậy bạn cần thêm một chút mã để phân chia đầu ra thành các khối 76 char và tham gia với \r\n.
Peter Taylor

@PeterTaylor đã sửa.
Tony Ellis

0

Thạch , 38 byte

s3z0Zµḅ⁹b64‘ịØb)FṖ³LN%3¤¡s4z”=Z;€“ƽ‘Ọ

Hãy thử trực tuyến!

Vì (hầu hết) mọi câu trả lời khác đều đáp ứng yêu cầu RFC2045 là "nhiều nhất là 76 ký tự trên mỗi dòng có dòng kết thúc \r\n", tôi đã làm theo nó.

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

s3z0Zµḅ⁹b64‘ịØb)FṖ³LN%3¤¡s4z”=Z;€“ƽ‘Ọ    Monadic main link. Input: list of bytes

s3z0Z    Slice into 3-item chunks, transpose with 0 padding, transpose back
         Equivalent to "pad to length 3n, then slice into chunks"

µḅ⁹b64‘ịØb)    Convert each chunk to base64
 ḅ⁹b64         Convert base 256 to integer, then to base 64
      ‘ịØb     Increment (Jelly is 1-based) and index into base64 digits

FṖ³LN%3¤¡s4z”=Z    Add correct "=" padding
F                  Flatten the list of strings to single string
 Ṗ      ¡          Repeat "remove last" n times, where
  ³LN%3¤             n = (- input length) % 3
         s4z”=Z    Pad "=" to length 4n, then slice into 4-item chunks

;€“ƽ‘Ọ    Add "\r\n" line separator
;€         Append to each line:
  “ƽ‘       Codepage-encoded list [13,10]
      Ọ    Apply `chr` to numbers; effectively add "\r\n"

Giải nén cơ sở có thể được sử dụng ở đây, nhưng ṃØbṙ1¤hơi lâu cho một thao tác đơn giản.
dùng202729

Có thể đáng để yêu cầu Dennis chế tạo nguyên tử giải nén xoay-bazơ.
dùng202729

Thất bại cho 0,0,0.
dùng202729
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.