使用Base64.encode时的Ruby字符编码

时间:2013-05-16 19:22:28

标签: ruby character-encoding base64

查看Ruby的Base64.encode的源代码在Base64中编码该数据之前,我无法确定将字符串转换为什么字符编码(如果有的话)。在Base64中编码的Utf-8字符串将与在Base64中编码的Utf-16字符串有很大不同。 Ruby是否会对此操作做出任何承诺?

2 个答案:

答案 0 :(得分:28)

在base64中编码和解码utf-8字符串的示例:

text = "intérnalionálização"
 => "intérnalionálização"
text.encoding
 => #<Encoding:UTF-8>
encoded = Base64.encode64(text)
 => "aW50w6lybmFsaW9uw6FsaXphw6fDo28=\n"
encoded.encoding
 => #<Encoding:US-ASCII>
decoded = Base64.decode64(encode)
 => "int\xC3\xA9rnalion\xC3\xA1liza\xC3\xA7\xC3\xA3o"
decoded.encoding
 => #<Encoding:US-ASCII>
decoded = decoded.force_encoding('UTF-8')
 => "intérnalionálização"
decoded.encoding
 => #<Encoding:UTF-8>

答案 1 :(得分:10)

fine manual有这样说:

  

<强> encode64(bin)中
  返回Base64编码的bin版本。此方法符合RFC 2045。

RFC 2045的第6.8节说:

  

<强> 6.8。 Base64 Content-Transfer-Encoding

     

Base64 Content-Transfer-Encoding旨在以不需要人类可读的形式表示任意八位字节序列。 [...]

     

使用65个字符的US-ASCII子集,每个可打印字符可以表示6位。 (额外的第65个字符“=”用于表示特殊处理功能。)

因此Base64将 bytes 编码为ASCII。如果这些字节实际上代表UTF-8编码的字符串,则UTF-8字符串将被分解为单个字节,并且这些字节将被转换为Base64;例如,如果您有一个UTF-8字符串'µ',那么您最终将字节0xc20xb5(按此顺序)编码为Base64表示"wrU=\n" 。如果您从二进制字符串"\xc2\xb5"开始(恰好匹配'µ'的UTF-8版本),那么您将得到相同的"wrU=\n"输出。

当您解码"wrU=\n"时,您将获得字节"\xc2\xb5",并且您必须知道这些字节应该是UTF-8编码的文本而不是某些任意blob的位。这就是为什么你有单独的内容类型和字符集元数据附加到Base64。

类似地,如果你有一个UTF-16字符串,那么它将被分成字节,这些字节将被编码,就像任何其他字节字符串一样。当然,由于字节顺序问题,这种情况稍微复杂一些,但这就是为什么我们有内容类型和字符集标题和BOM。

重点是Base64使用 bytes ,而不是字符。什么格式(UTF-8文本,UTF-16文本,PNG图像......)是别人的问题。 Base64只是将字节流转换为US ASCII的子集,然后再转换为字节;必须单独指定这些字节的格式。


我在源头做了一些探讨,结果可能会引起人们的兴趣,即使它们并不完全相关。 encode64 method就是这样:

def encode64(bin)
  [bin].pack("m")
end

然后,如果你浏览Array#pack

static VALUE
pack_pack(VALUE ary, VALUE fmt)
{
    /*...*/
    int enc_info = 1;       /* 0 - BINARY, 1 - US-ASCII, 2 - UTF-8 */

并密切关注enc_info,您会看到'm'格式会单独留下enc_info,因此打包的字符串将以US-ASCII形式出现,因此{{1将按预期生成US ASCII输出。