Patrząc na źródło Ruby's Base64.encode Nie mogę określić, który kodowanie znaków jest konwertowane na, jeśli w ogóle, przed zakodowaniem tych danych w Base64. Łańcuch Utf-8 zakodowany w Base64 będzie dużo inny niż łańcuch Utf-16 zakodowany w Base64. Czy Ruby składa jakieś obietnice dotyczące tej operacji?Kodowanie znaków w języku Ruby przy użyciu Base64.encode
Odpowiedz
fine manual ma do powiedzenia:
encode64 (bin)
Zwraca Base64- zakodowana wersja bin. Metoda ta jest zgodna z RFC 2045.
sekcja 6.8 RFC 2045 mówi:
6.8. Base64 Content-Transfer-Kodowanie
Kodowanie zawartości Base64 służy do reprezentowania dowolnych sekwencji oktetów w postaci, która nie musi być czytelna dla człowieka. [...]
Używany jest 65-literowy podzbiór US-ASCII, umożliwiający reprezentację 6 bitów na jedną drukowaną literę. (Dodatkowa 65-ci znak „=” jest używany do oznaczenia specjalną funkcję przetwarzania.)
Więc Base64 koduje bajtów w ASCII. Jeśli te bajty faktycznie reprezentują łańcuch zakodowany w UTF-8, to ciąg znaków UTF-8 zostanie podzielony na poszczególne bajty, a bajty te zostaną przekonwertowane na Base64; na przykład, jeśli masz ciąg znaków UTF-8 'µ'
, to skończy się kodowanie bajtów 0xc2
i 0xb5
(w tej kolejności) do reprezentacji Base64 "wrU=\n"
. Jeśli zaczynasz od binarnego ciągu znaków "\xc2\xb5"
(który akurat pasuje do wersji UTF-8 z 'µ'
), otrzymasz ten sam wynik "wrU=\n"
.
Po dekodowaniu "wrU=\n"
, otrzymasz bajty "\xc2\xb5"
i będziesz musiał wiedzieć, że te bajty mają być kodowane w UTF-8, a nie jakaś dowolna kropla bitów. Właśnie dlatego masz oddzielny typ zawartości i zestaw metadanych zestawu znaków dołączony do Base64.
Podobnie, jeśli masz ciąg znaków UTF-16, to zostanie on podzielony na bajty, a bajty te zostaną zakodowane tak jak każdy inny ciąg bajtów. Oczywiście ta sprawa jest nieco bardziej skomplikowana z powodu problemów z kolejnością bajtów, ale właśnie dlatego mamy nagłówki typów treści i zestawów znaków oraz LM.
Najważniejsze jest to, że Base64 współpracuje z bajtami, a nie znakami. Jaki format (tekst w formacie UTF-8, tekst w formacie UTF-16, obraz PNG, ...) jest problemem kogoś innego. Base64 po prostu konwertuje strumień bajtowy na podzbiór US ASCII, a następnie z powrotem do bajtów; format tych bajtów musi być określony osobno.
Zrobiłem trochę szturchania w źródle, a wyniki mogą być interesujące, nawet jeśli nie są całkowicie odpowiednie.encode64
method jest po prostu tak:
def encode64(bin)
[bin].pack("m")
end
Następnie, jeśli spojrzeć przez Array#pack
:
static VALUE
pack_pack(VALUE ary, VALUE fmt)
{
/*...*/
int enc_info = 1; /* 0 - BINARY, 1 - US-ASCII, 2 - UTF-8 */
i pilnować enc_info
, zobaczysz, że Formatowanie 'm'
pozostawi enc_info
sam tak zapakowanym łańcucha wyjdzie jako US-ASCII, a więc encode64
będzie wytwarzać dane wyjściowe ASCII w USA zgodnie z oczekiwaniami.
Przykładem do kodowania i dekodowania ciąg UTF-8 w 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>
Interesujące. Ciąg zwrócony z dekodowania64 to US-ASCII i zawiera garść znaków zbiegów. Przypuszczam, że jest to całkiem niezły wskaźnik, że konwertuje go na US-ASCII, zanim go również zakoduje kod base64. – Brent
Aby zrozumieć: http://api.rubyonrails.org/classes/Base64.html i http://apidock.com/ruby/Array/pack –
Jeśli chcesz wypróbować kod Victora w sesji irbowej, upewnij się, że Najpierw musisz "wymagać" bazy64. – Gokul
Zgadzam się z moimi podejrzeniami w komentarzach odpowiedzi Wiktora. Dziękuję za potwierdzenie. – Brent