10

Redisにテキストメッセージのキューがあります。redisのメッセージが次のようなものだとしましょう:

"niño" 

(非標準文字を見つけます)。

railsアプリは、メッセージのキューを表示します。ローカルでテストすると(Rails 3.2.2、Ruby 1.9.3)、すべて問題ありませんが、Heroku杉(Rails 3.2.2、Ruby 1.9.2があると思います)では、悪名高いエラーが発生します。ActionView::Template::Error (invalid byte sequence in UTF-8)

私がオンラインで見つけることができるすべてを読んで再読した後、私はまだこれを修正する方法について立ち往生しています。

どんな助けや正しい方向への指摘も大歓迎です!

編集:

私はなんとか解決策を見つけることができました。私はIconvを使用することになりました:

string = Iconv.iconv('UTF-8', 'ISO-8859-1', message)[0]

私の場合、私が見つけた提案された答えはどれもうまくいかないようです。

4

1 に答える 1

37

Herokuでは、アプリがRedisから「niño」というメッセージを受信すると、実際には4バイトを取得しています。

 0x6e 0x69 0xf1 0x6f

これは、 ISO-8859-1として解釈される場合、文字n、、、およびに対応します。iño

ただし、Railsアプリは、これらのバイトがUTF-8として解釈される必要があると想定し、ある時点でこの方法でデコードしようとします。このシーケンスの3番目のバイトである0xf1は、次のようになります。

1 1 1 1 0 0 0 1

これをウィキペディアページの表と比較すると、このバイトは4バイト文字の先頭バイト(パターンに一致11110xxx)であり、その後にすべてパターンに一致する3つの継続バイトが続く必要があることがわかります10xxxxxx。そうではなく、代わりに次のバイトは0x6f(01101111)であるため、これは無効なutf-8バイトシーケンスであり、表示されるエラーが発生します。

使用:

string = message.encode('utf-8', 'iso-8859-1')

(またはIconv同等のもの)は、RubyにmessageISO-8859-1エンコードとして読み取り、UTF-8エンコードで同等の文字列を作成するように指示します。これにより、問題なく使用できます。(別の方法として、Rubyに文字列の正しいエンコーディングを指示することもできますがforce_encoding、後でUTF-8文字列とISO-8859-1文字列を混在させようとすると問題が発生する可能性があります)。

UTF-8では、文字列「niño」はバイトに対応します。

0x6e 0x69 0xc3 0xb1 0x6f

最初、2番目、最後のバイトは同じであることに注意してください。文字はñ2バイトとしてエンコードされます0xc3 0xb1。これらをバイナリで書き出して、ウィキペディアの記事の表と比較すると、ISO-8859-1エンコーディングである0xf1がエンコードされていることがわかりますñ(最初の256個のUnicodeコードポイントはISO-8859-1と一致するため)。

これらの5バイトを取得し、ISO-8859-1として扱う場合、これらは文字列に対応します。

niño

ISO-8859-1コードページを見ると、0xc3はにマップされÂ、0xb1はにマップされ±ます。

つまり、ローカルマシンで起こっていることは、アプリが0x6e 0x69 0xc3 0xb1 0x6fRedisから5バイトを受信して​​いることです。これは、「niño」のUTF-8表現です。0x6e 0x69 0xf1 0x6fHerokuでは、ISO-8859-1表現である4バイトを受信して​​います。

問題の本当の解決策は、Redisに入れられる文字列がすべてすでにUTF-8(または少なくともすべて同じエンコーディング)であることを確認することです。私はRedisを使用していませんが、簡単なGoogleからわかるように、文字列エンコーディングには関係なく、与えられたバイトを返すだけです。データをRedisに配置しているプロセスを確認し、エンコードが適切に処理されることを確認する必要があります。

于 2012-04-07T21:32:04.573 に答える