Bayt dizisini base64 biçimine dönüştürme


10

Senin görevin bir bayt dizisi (yani: 0 ile 255 arasında bir tamsayılar dizisi), base64 dönüştüren bir işlev / program yazmaktır.

Yerleşik base64 kodlayıcıların kullanımına izin verilmez.

Gerekli base64 uygulaması RFC 2045'tir. ("+", "/" Ve "=" ile zorunlu doldurma kullanılarak)

En kısa kod (bayt cinsinden) kazanır!

Misal:

Girdi (int dizi): [99, 97, 102, 195, 169]

Çıktı (dize): Y2Fmw6k=


Bu ne tür bir rekabet?
Cilan

Does kodlayıcı yerleşik base64 yanı tamsayılar manipüle sadece ikili-metin kodlayıcılar veya fonksiyonları kapsamaktadır?
Dennis

1
Açıklığa kavuşturmak için: 1 2Bağımsız değişken için geri dönen bir işlevi kullanabilir miyim 66?
Dennis

1
Base64'ün 9 standart veya 4 standart olmayan sürümü vardır. =Dolgu için referansınız 4'e düşürür. Hangisini istiyorsunuz? Veya maksimum satır uzunluklarına sahip olmayan standart dışı bir varyant mı istiyorsunuz?
Peter Taylor

O ya RFC 4648 tarafından belirtilen "standart" ya da MIME türleri, RFC 2045 tarafından kullanılan sürümü atıfta sanırım. Bunlar farklı, bu yüzden açıklama çok yararlı olacaktır.
yarı ekstrinsik

Yanıtlar:


4

JavaScript, 177 187 198 karakterler

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}

Satır sonu eklemek için \r\n, her 76. karakterden sonra koda 23 karakter ekleyin:

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}

Demo kodu:

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)})
 )
);


Güzel çözüm! Bazı ES6 özelliklerini kullanarak ve bazı çoğaltmaları kaldırarak bazı baytları tıraş edebilirsiniz: Yorumlarla kısaltılmış kod
Craig Ayre

@CraigAyre, yapıcı girdi için teşekkürler. ES6 tamamlanmadı ve bu zorluğun asıl yayınlandığı sırada mevcut değildi. Codegolf.meta'da önerildiği gibi , kısaltılmış ES6 sürümünü gönderebilir ve rakip olmayan olarak işaretleyebilirsiniz.
Tomas Langkaas

Endişeye gerek yok, orijinal posta tarihini iki kez kontrol etmem için benim hatam! Çözümünüzün hayranıyım, bu yüzden başka bir yayın göndermeyeceğim, ancak bağlantı için teşekkürler. Alfabe çoğaltmasını kaldıran şablon değişmez mantığı, aynı sayıda baytta ES5'e dönüştürülebilir, çok fazla tasarruf yapmaz, ancak her küçük sayım!
Craig Ayre

@CraigAyre, bahşiş için tekrar teşekkürler, base64 sembollerini daha da sıkıştırmanın başka bir yolunu buldu (bu da daha geriye dönük uyumlu hale geldi - şimdi eski IE'de de çalışmalıdır).
Tomas Langkaas

3

32 bit x86 derlemesi, 59 bayt

Bayt kodu:

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

demontaj:

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

Esi giriş arabelleğine, edi çıkış arabelleğine işaret ederek b64encode'u arayın.

Hat sarma kullanılmazsa daha da küçülebilir.


1

perl, 126 bayt

stdin'i okur, stdout'a çıktılar

$/=$\;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

ungolfed:

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;
}

Sorunun RFC 2045 gerektirdiği açıklandı, bu nedenle çıktıyı 76 karakterlik parçalara bölmek ve katılmak için biraz kod eklemeniz gerekiyor \r\n.
Peter Taylor

1

Perl, 147 bayt

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}

İşlev, girdi olarak bir tamsayı listesi alır ve base64 kodlu dizgiyi çıktılar.

Misal:

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

baskılar

Y2Fmw6kA

Ungolfed:

Ara adımları da görselleştiren sürüm:

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;
}

Çıktı:

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=

Testler:

Test dizeleri, Base64 için Wikipedia makalesindeki örneklerin sorusundaki örnekten gelir .

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

Test çıktısı:

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZSO=

YW55IGNhcm5hbCBwbGVhc3VyZSO=

YW55IGNhcm5hbCBwbGVhc3VyZB==

YW55IGNhcm5hbCBwbGVhc3Vy

YW55IGNhcm5hbCBwbGVhc3F=

YW55IGNhcm5hbCBwbGVhcD==

cGxlYXN1cmUu

bGVhc3VyZSO=

ZWFzdXJlLC==

YXN1cmUu

c3VyZSO=

Sorunun RFC 2045 gerektirdiği açıklandı, bu nedenle çıktıyı 76 karakterlik parçalara bölmek ve katılmak için biraz kod eklemeniz gerekiyor \r\n.
Peter Taylor

@PeterTaylor: Teşekkürler, RFC 2045 için cevabı güncelledim.
Heiko Oberdiek

Bu tam cevap için bravo. Zorunlu satır sonlarını dahil etmek (OP'de "RFC 2045" belirterek) aslında bir hataydı, aslında bu kısmı göz ardı edebilirsiniz. Üzgünüm :)
xem

1

Python, 234 karakter

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:]

Sorunun RFC 2045 gerektirdiği açıklandı, bu nedenle çıktıyı 76 karakterlik parçalara bölmek ve katılmak için biraz kod eklemeniz gerekiyor \r\n.
Peter Taylor

@PeterTaylor: sabit.
Keith Randall

1

GolfScript, 80 (77) bayt

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

Yukarıdaki son satır hariç, bir satıra tam olarak 76 karakter sığacaktır. Tüm satırlar CRLF ile sonlandırılır.

RFC 2045'in değişken, maksimum satır uzunluğunu 76 karakter belirlediğini unutmayın , bu nedenle güzel çıktı maliyetiyle 3 ek bayt kaydedebiliriz.

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

Yukarıdaki satır, 0, 1 veya 2 =karakter içerebilen son satır hariç, her satıra bir karakter basacaktır . GolfScript ayrıca, RFC 2045'e göre kod çözme yazılımı tarafından yoksayılması gereken son bir LF ekleyecektir.

Misal

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

Nasıl çalışır

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

<?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;

Çevrimiçi deneyin!

("$s+/=")Dizeyi bir dizi ile değiştirebilirsinizarray_merge(range(A,Z),range(a,z),range(0,9),["+","/","="])

Yalnızca hangi bayt sayısının izin verilmeyen bir yerleşik ile ulaşabileceğini karşılaştırmak için

PHP , 45 bayt

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

Çevrimiçi deneyin!


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}

Tarayıcınız ES6'yı desteklemiyorsa, bu sürümle (262B) deneyebilirsiniz:

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])döner "Y2Fmw6k=".


76 karakterlik parçalara bölüştürülecek kod nerede \r\n?
Peter Taylor

0

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

Biraz soluksuz:

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

Örnek :

Python'un yerleşik base64 modülü, bu örnekte yalnızca eişlevin doğru çıktıya sahip olmasını sağlamak için kullanılır , eişlevin kendisi bunu kullanmaz.

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

Sorunun RFC 2045 gerektirdiği açıklandı, bu nedenle çıktıyı 76 karakterlik parçalara bölmek ve katılmak için biraz kod eklemeniz gerekiyor \r\n.
Peter Taylor

@PeterTaylor düzeltildi.
Tony Ellis

0

Jöle , 38 bayt

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

Çevrimiçi deneyin!

(Hemen hemen her cevap) RFC2045'in "satır sonu olan satır başına en fazla 76 karakter" gereksinimini karşıladığı için \r\n, bunu takip ettim.

Nasıl çalışır

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"

Temel dekompresyon burada kullanılabilir, ancak ṃØbṙ1¤basit bir işlem için biraz uzun.
user202729

Dennis'den döndürülmüş baz dekompresyon atomu yapmasını istemek faydalı olabilir.
user202729

İçin başarısız 0,0,0.
user202729
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.