20

Ruby の Base64.encode のソースを見ると、そのデータを Base64 でエンコードする前に、文字列がどの文字エンコーディングに変換されるかを判断できません。Base64 でエンコードされた Utf-8 文字列は、Base64 でエンコードされた Utf-16 文字列とは大きく異なります。この操作に関して、Ruby は何らかの約束をしていますか?

4

2 に答える 2

36

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>
于 2013-05-16T20:11:46.037 に答える
12

細かいマニュアルには次のように書かれています。

encode64(bin) Bin
の Base64 エンコード バージョンを返します。この方法は、RFC 2045 に準拠しています。

RFC 2045のセクション 6.8 には次のように記載されています。

6.8. Base64 コンテンツ転送エンコーディング

Base64 Content-Transfer-Encoding は、人間が判読できる必要のない形式で任意のオクテット シーケンスを表すように設計されています。[...]

US-ASCII の 65 文字のサブセットが使用され、印刷可能な文字ごとに 6 ビットを表すことができます。(余分な 65 番目の文字「=」は、特別な処理機能を示すために使用されます。)

したがって、Base64 はバイトを ASCII にエンコードします。これらのバイトが実際に UTF-8 でエンコードされた文字列を表している場合、UTF-8 文字列は個々のバイトに分割され、それらのバイトは Base64 に変換されます。たとえば、UTF-8 文字列がある場合'µ'は、バイト0xc20xb5(この順序で) Base64 表現にエンコードすることになり"wrU=\n"ます。バイナリ文字列"\xc2\xb5"(たまたま の UTF-8 バージョンと一致する'µ') から始めると、同じ"wrU=\n"出力が得られます。

をデコードする"wrU=\n"と、バイトが取得"\xc2\xb5"されます。これらのバイトは、ビットの任意の塊ではなく、UTF-8 でエンコードされたテキストであると想定されていることを知っておく必要があります。これが、コンテンツ タイプと文字セットのメタ データが Base64 にアタッチされている理由です。

同様に、UTF-16 文字列がある場合、それはバイトに分割され、それらのバイトは他のバイト文字列と同様にエンコードされます。もちろん、このケースはバイト オーダーの問題により少し複雑ですが、コンテンツ タイプと文字セットのヘッダーと BOM があるのはそのためです。

要点は、Base64は文字ではなくバイトで動作するということです。どの形式 (UTF-8 テキスト、UTF-16 テキスト、PNG 画像など) かは、他の誰かの問題です。Base64 は、バイト ストリームを US ASCII のサブセットに変換してからバイトに戻すだけです。これらのバイトの形式は個別に指定する必要があります。


ソースを調べてみましたが、完全に関連性がなくても、結果は興味深いものになるかもしれません。encode64メソッドはこれだけです:

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 */

に注目すると、フォーマットがそのままになるため、パックされた文字列が US-ASCIIとして出力され、期待どおりに US ASCII 出力が生成されるenc_infoことがわかります。'm'enc_infoencode64

于 2013-05-17T00:21:28.017 に答える