바이트 배열을 base64로 변환


10

당신의 임무는 바이트 배열 (예 : 0에서 255의 정수 배열)을 base64로 변환하는 함수 / 프로그램을 작성하는 것입니다.

내장 base64 엔코더 사용은 허용되지 않습니다.

필수 base64 구현은 RFC 2045입니다 ( "+", "/"및 "="로 필수 패딩 사용)

가장 짧은 코드 (바이트)가 이깁니다!

예:

입력 (int array) : [99, 97, 102, 195, 169]

출력 (문자열) : Y2Fmw6k=


이것은 어떤 유형의 경쟁입니까?
Cilan

합니까 인코더가 내장 된 64 기수 뿐만 아니라 정수를 조작 이진 - 텍스트 인코더 또는 기능을 포함?
Dennis

1
명확히하기 위해 : 1 2인수에 대해 반환하는 함수를 사용할 수 있습니까 66?
Dennis

1
base64 에는 9 개의 표준화 또는 4 개의 비표준 버전이 있습니다. =패딩 에 대한 참조는 4로 좁 힙니다. 어느 것을 원하십니까? 또는 최대 줄 길이가없는 비표준 변형을 원하십니까?
피터 테일러

RFC 4648에 의해 지정된 "표준"또는 MIME 유형에 의해 사용 된 버전 인 RFC 2045를 참조한 것 같습니다. 이것들은 다르므로 설명이 매우 유용 할 것입니다.
세미 외부

답변:


4

자바 스크립트, 177 187 198 문자

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}

\r\n바꿈을 추가하려면, 각 76 번째 문자 다음에 코드에 23자를 추가하십시오.

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}

데모 코드 :

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


좋은 해결책! 일부 ES6 기능을 사용하고 일부 중복을 제거하여 일부 바이트를 줄일 수 있습니다. 주석이있는 코드 단축
Craig Ayre

@CraigAyre, 건설적인 의견을 보내 주셔서 감사합니다. ES6은이 도전이 처음 게시 된 시점에 확정되지 않았으며 이용 가능합니다. codegolf.meta 에서 제안한대로 단축 ES6 버전을 게시하고 경쟁이 아닌 것으로 표시 할 수 있습니다.
Tomas Langkaas 2016 년

걱정하지 마십시오. 원래 게시 날짜를 두 번 확인하지 않은 것에 대한 내 잘못! 나는 귀하의 솔루션의 팬이므로 다른 게시물을 게시하지는 않지만 링크를 주셔서 감사합니다. 알파벳 중복을 제거한 템플릿 리터럴 로직은 동일한 바이트 수로 ES5로 변환 될 수 있으며 많은 수를 절약 할 수 있지만 모든 작은 수를 절약 할 수는 없습니다!
Craig Ayre 2016 년

@CraigAyre는 팁에 다시 한 번 감사의 말씀을 전하며 base64 기호를 훨씬 더 압축하는 또 다른 방법을 찾았습니다.
Tomas Langkaas 2016 년

3

32 비트 x86 어셈블리, 59 바이트

바이트 코드 :

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

분해 :

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와 출력 버퍼를 가리키는 edi로 b64encode를 호출하십시오.

줄 바꿈을 사용하지 않으면 더 작게 만들 수 있습니다.


1

펄, 126 바이트

stdin을 읽고 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

언 골프 :

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

RFC 2045가 필요하다는 질문이 명확 해 졌으므로 약간의 코드를 추가하여 출력을 76 문자 청크로 나누고와 결합해야 \r\n합니다.
피터 테일러

1

펄, 147 바이트

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}

이 함수는 정수 목록을 입력으로 받아 base64로 인코딩 된 문자열을 출력합니다.

예:

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

인쇄물

Y2Fmw6kA

언 골프 드 :

중간 단계를 시각화하는 버전 :

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

산출:

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=

테스트 :

테스트 문자열은 문제의 예제에서 Base64 에 대한 Wikipedia 기사의 예제에서 제공 됩니다.

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

테스트 출력 :

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZSO=

YW55IGNhcm5hbCBwbGVhc3VyZSO=

YW55IGNhcm5hbCBwbGVhc3VyZB==

YW55IGNhcm5hbCBwbGVhc3Vy

YW55IGNhcm5hbCBwbGVhc3F=

YW55IGNhcm5hbCBwbGVhcD==

cGxlYXN1cmUu

bGVhc3VyZSO=

ZWFzdXJlLC==

YXN1cmUu

c3VyZSO=

RFC 2045가 필요하다는 질문이 명확 해 졌으므로 약간의 코드를 추가하여 출력을 76 문자 청크로 나누고와 결합해야 \r\n합니다.
피터 테일러

@PeterTaylor : 감사합니다, 나는 RFC 2045에 대한 답변을 업데이트 한
HEIKO Oberdiek

이 매우 완전한 답변에 대한 브라보. 필수 줄 바꿈을 포함하면 (OP에서 "RFC 2045"를 지정하여) 실제로 오류 였으므로 실제로 해당 부분을 무시할 수 있습니다. 죄송합니다 :)
xem은

1

파이썬, 234 자

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

RFC 2045가 필요하다는 질문이 명확 해 졌으므로 약간의 코드를 추가하여 출력을 76 문자 청크로 나누고와 결합해야 \r\n합니다.
피터 테일러

@PeterTaylor : 수정되었습니다.
Keith Randall

1

GolfScript, 80 (77) 바이트

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

위의 내용은 마지막 줄을 제외하고 한 줄에 정확히 76 자에 맞습니다. 모든 행은 CRLF로 종료됩니다.

RFC 2045는 최대 76 자 길이의 변수를 지정 하므로 출력이 꽤 비싸기 때문에 3 바이트를 더 절약 할 수 있습니다.

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

위의 내용은 0, 1 또는 2 개의 =문자를 포함 할 수있는 마지막 줄을 제외하고 한 줄에 한 문자 씩 인쇄합니다 . GolfScript는 RFC 2045에 따라 디코딩 소프트웨어로 무시해야하는 최종 LF도 추가합니다.

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

작동 원리

~          # 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 바이트

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

온라인으로 사용해보십시오!

문자열 ("$s+/=")을 배열로 바꿀 수 있습니다array_merge(range(A,Z),range(a,z),range(0,9),["+","/","="])

허용되지 않는 내장 함수로 도달 할 수있는 바이트 수를 비교하기 위해서만

PHP , 45 바이트

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

온라인으로 사용해보십시오!


0

자바 스크립트 (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}

브라우저가 ES6을 지원하지 않는 경우이 버전 (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])을 반환합니다 "Y2Fmw6k=".


그것을 76 문자 덩어리로 나누는 코드는 어디에 있습니까 \r\n?
피터 테일러

0

파이썬- 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

언 골프 :

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

:

파이썬의 내장 base64 모듈은이 예제에서만 e함수가 올바른 출력을 가지고 있는지 확인하기 위해 사용되며 e함수 자체는 사용하지 않습니다.

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

RFC 2045가 필요하다는 질문이 명확 해 졌으므로 약간의 코드를 추가하여 출력을 76 문자 청크로 나누고와 결합해야 \r\n합니다.
피터 테일러

@PeterTaylor가 수정되었습니다.
Tony Ellis

0

젤리 , 38 바이트

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

온라인으로 사용해보십시오!

(거의) 다른 모든 답변은 "줄 끝으로 줄당 최대 76 자"의 RFC2045 요구 사항을 다루 \r\n므로 따라갔습니다.

작동 원리

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"

여기서 기본 압축 풀기를 사용할 수 있지만 ṃØbṙ1¤간단한 조작을하기에는 시간이 너무 깁니다.
user202729 4

Dennis에게 회전축 감압 원자를 만들도록 요청하는 것이 좋습니다.
user202729

에 실패합니다 0,0,0.
user202729
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.