Perl, 147 bytes
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}
The function takes a list of integers as input and outputs the string, base64 encoded.
Example:
print b(99, 97, 102, 195, 169)
prints
Y2Fmw6kA
Ungolfed:
Version that also visualizes the intermediate steps:
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;
}
Output:
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=
Tests:
The test strings come from the example in the question the examples in the Wikipedia article for 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.";
Test output:
TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZSO=
YW55IGNhcm5hbCBwbGVhc3VyZSO=
YW55IGNhcm5hbCBwbGVhc3VyZB==
YW55IGNhcm5hbCBwbGVhc3Vy
YW55IGNhcm5hbCBwbGVhc3F=
YW55IGNhcm5hbCBwbGVhcD==
cGxlYXN1cmUu
bGVhc3VyZSO=
ZWFzdXJlLC==
YXN1cmUu
c3VyZSO=
1 2
for the argument66
? \$\endgroup\$=
for padding narrows it down to 4. Which one do you want? Or do you want a non-standard variant which doesn't have maximum line lengths? \$\endgroup\$