2012-04-06 14 views
11

私はRedisでテキストメッセージのキューを持っています。赤字のメッセージが次のようなものだとしましょう:Rails、Heroku、UTF-8エラーの無効なバイトシーケンス

"niño" 

(非標準文字に点滅)

railsアプリケーションは、メッセージのキューを表示します。私がローカルでテストすると(Rails 3.2.2、Ruby 1.9.3)、すべて正常ですが、Heroku Cedar(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] 

なし。

あなたのアプリがRedisのからのメッセージ「ニーニョ」を受信Herokuの、オン
+0

私はheroku labs ruby​​ 1.9.3でインストールしましたが、同じエラーが表示されます。 – klaut

+2

Ruby 1.9.3でIconvが必要な場合、この警告が表示されます: 'iconvは今後廃止され、代わりにString#encodeを使用してください。'あなたのソリューションに相当するものは 'string.force_encoding( 'iso-8859- 1 ')。encode(' utf-8 ') '。 – matt

+2

'string = message.encode( 'utf-8'、 'iso-8859-1')'が良いかもしれません。 – matt

答えて

38

、それが実際に取得された4バイト:

0x6e 0x69 0xf1 0x6f 

ISO-8859-1として解釈する際の文字に対応niño

しかし、あなたのRailsアプリケーションでは、これらのバイトはUTF-8と解釈されなければならず、ある時点ではこのようにデコードしようとします。このシーケンスの3番目のバイトは、0xf1は、次のようになります。

1 1 1 1 0 0 0 1 

あなたはtable on the Wikipedia pageにこれを比較した場合、あなたはこのバイトが4つのバイト文字の先頭バイトで見ることができます(それがパターン11110xxxにマッチする)、およびそれに続くパターンがすべて10xxxxxxの3つの続きバイトに続く必要があります。そうではなく、次のバイトが0x6f(01101111)なので、これは無効なutf-8バイトシーケンスであり、表示されるエラーになります。使用

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

(または同等のIconv)はISO-8859-1でエンコードとしてmessageを読み取るために、次にあなたがして使用することができUTF-8エンコーディングに同等の文字列を作成するために、ルビーを伝えます問題なく。 (代わりにforce_encodingを使用して、Rubyに文字列の正しいエンコーディングを伝えることができますが、後でUTF-8とISO-8859-1の文字列を混ぜようとすると問題が発生する可能性があります)。

UTF-8において、文字列「ニノ」バイトに対応する:第一、第二及び最後のバイトが同一である

0x6e 0x69 0xc3 0xb1 0x6f 

留意されたいです。 ñ文字は2バイト0xc3 0xb1としてエンコードされます。これらをバイナリで書き出し、Wikipediaの記事の表と比較すると、ISO-8859-1のエンコーディング0xf1がñ(最初の256個のUnicodeコードポイントはISO-8859-1と一致しているため) 。

あなたはこれらの5つのバイトを取ると、ISO-8859-1であるとして扱う場合

は、その後、彼らは ±から Âにマップ0xc3 ISO-8859-1 codepageを見てみると、文字列

niño 

、との0xB1マップに対応しています。

あなたのローカルマシンで起こっていることは、あなたのアプリが "niño"のUTF-8表現であるRedisから0x6e 0x69 0xc3 0xb1 0x6fの5バイトを受け取っていることです。 Herokuでは、4バイトの0x6e 0x69 0xf1 0x6fを受け取ります。これはISO-8859-1の表現です。

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

+0

非常に徹底的です。 +1 – coreyward

+0

非常に良い答え、ありがとう! – klaut

+2

うわー、これは答えがどのように見えるかです! – Cristian