Su Heroku, quando la vostra applicazione riceve il messaggio "Nino" da Redis, esso è in realtà sempre i quattro byte:
0x6e 0x69 0xf1 0x6f
che, se interpretato come ISO-8859-1 corrispondono ai personaggi n
, i
, ñ
e o
.
Tuttavia, l'app Rails presuppone che questi byte debbano essere interpretati come UTF-8 e, a un certo punto, tenta di decodificarli in questo modo. Il terzo byte in questa sequenza, 0xf1 assomiglia a questo:
1 1 1 1 0 0 0 1
Se si confronta questo al table on the Wikipedia page, è possibile vedere questo byte è il byte iniziale di un carattere quattro byte (che corrisponde al modello 11110xxx
), e come tale dovrebbe essere seguito da altri tre byte di continuazione che corrispondono tutti allo schema 10xxxxxx
. Non lo è, invece il byte successivo è 0x6f (01101111
), quindi questa è una sequenza di byte utf-8 non valida e ottieni l'errore che vedi.
Usando:
string = message.encode('utf-8', 'iso-8859-1')
(o l'equivalente Iconv
) dice a Ruby per leggere message
come ISO-8859-1 codificato, e quindi per creare la stringa equivalente in codifica UTF-8, che è quindi possibile utilizzare senza problemi. (Un'alternativa potrebbe essere quella di usare force_encoding
per dire a Ruby la corretta codifica della stringa, ma questo probabilmente causerà problemi in seguito quando proverai a mescolare le stringhe UTF-8 e ISO-8859-1).
In UTF-8, la stringa "niño" corrisponde ai byte:
0x6e 0x69 0xc3 0xb1 0x6f
noti che il primo, il secondo e ultimo byte sono uguali. Il carattere ñ
è codificato come i due byte 0xc3 0xb1
.Se li scrivi in binario e li confronti con la tabella nell'articolo di Wikipedia, vedrai che codificano 0xf1, che è la codifica ISO-8859-1 di ñ
(poiché i primi 256 codecoint unicode corrispondono a ISO-8859-1) .
Se si prende questi cinque byte e trattarli come ISO-8859-1, allora essi corrispondono alla stringa
niño
Guardando il ISO-8859-1 codepage, 0xc3 mappe di Â
, e le mappe 0xB1 a ±
.
Quindi, ciò che accade sul computer locale è che la tua app riceve i cinque byte 0x6e 0x69 0xc3 0xb1 0x6f
da Redis, che è la rappresentazione UTF-8 di "niño". Su Heroku riceve i quattro byte 0x6e 0x69 0xf1 0x6f
, che è la rappresentazione ISO-8859-1.
La vera soluzione al tuo problema sarà di assicurarti che le stringhe che vengono inserite in Redis siano già tutte UTF-8 (o almeno la stessa codifica). Non ho usato Redis, ma da quello che posso dire da un breve Google, non si occupa delle codifiche di stringhe, ma restituisce semplicemente tutti i byte che sono stati dati. Dovresti considerare qualunque processo stia inserendo i dati in Redis e assicurarsi che gestisca correttamente la codifica.
ho installato tramite heroku labs ruby 1.9.3, ma ottengo ancora lo stesso errore: | – klaut
Quando si richiede Iconv in Ruby 1.9.3 si ottiene questo avviso: 'iconv sarà deprecato in futuro, usare invece la codifica String #. L'equivalente della soluzione sarà qualcosa del tipo:' string.force_encoding ('iso-8859- 1 '). codificare (' utf-8') '. – matt
Oppure 'string = message.encode ('utf-8', 'iso-8859-1')' potrebbe essere migliore. – matt