2013-05-16 3 views
7

Глядя на источник Base64.encode Ruby, я не могу определить, какая кодировка символов строка преобразуется, если вообще, перед кодированием этих данных в Base64. Строка Utf-8, закодированная в Base64, будет сильно отличаться от строки Utf-16, закодированной в Base64. Предоставляет ли Ruby какие-либо обещания относительно этой операции?Кодировка символов Ruby при использовании Base64.encode

ответ

5

fine manual имеет это сказать:

encode64 (бин)
Возвращает Base64- закодированная версия bin. Этот метод соответствует RFC 2045.

Раздел 6.8 RFC 2045 говорит:

6.8. Base64 Content-Transfer-Encoding

Base64 Content-Transfer-Encoding предназначен для представления произвольных последовательностей октетов в форме, которая не нуждается в удобочитаемости. [...]

Используется 65-символьное подмножество US-ASCII, позволяющее представить 6 бит на печатный символ. (Дополнительный шестьдесят пятый символ "=", используется для обозначения специальной функции обработки.)

Так Base64 кодирует байт в ASCII. Если эти байты фактически представляют собой кодированную строку UTF-8, то строка UTF-8 будет разбита на отдельные байты, и эти байты будут преобразованы в Base64; например, если у вас есть строка UTF-8 'µ', тогда вы закончите кодирование байтов 0xc2 и 0xb5 (в указанном порядке) к представлению Base64 "wrU=\n". Если вы начинаете с двоичной строки "\xc2\xb5" (которая просто соответствует версии UTF-8 'µ'), вы получите то же самое "wrU=\n".

Когда вы декодируете "wrU=\n", вы получите байты "\xc2\xb5", и вам нужно будет знать, что эти байты должны быть кодированным текстом UTF-8, а не каким-либо произвольным блоком бит. Вот почему у вас есть отдельный тип контента и метаданные набора символов, прикрепленные к Base64.

Аналогично, если у вас есть строка UTF-16, она будет разбита на байты, и эти байты будут закодированы так же, как и любая другая строка байтов. Конечно, этот случай немного сложнее из-за проблем с порядком байтов, но поэтому у нас есть заголовки контента и заголовки символов и спецификации.

Главное, что Base64 работает с байтами, а не с символами. Какой формат (текст 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, и поэтому encode64 будет производить US ASCII-выход, как ожидалось.

+0

Это согласуется с моими подозрениями в комментариях ответа Виктора. Спасибо, что подтвердили. – Brent

19

Пример для кодирования и декодирования строки UTF-8 в base64:

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> 
+0

Интересно. Строка, возвращаемая с decode64, является US-ASCII и содержит кучу экранированных символов. Я полагаю, что это неплохой показатель того, что он преобразует его в US-ASCII до того, как он также будет кодировать base64. – Brent

+1

Чтобы понять: http://api.rubyonrails.org/classes/Base64.html и http://apidock.com/ruby/Array/pack –

+1

Если вы хотите попробовать код Виктора в сеансе irb, убедитесь, что вы сначала требуете «base64». – Gokul