web-dev-qa-db-ja.com

非ASCII文字をASCII-8BITからUTF-8に変換する

リモートサイトからテキストを取得し、デフォルトでutf-8を使用するRuby 1.9/Rails 3アプリにロードしようとしています。

問題のあるテキストの例を次に示します。

Cancer Res; 71(3); 1-11. ©2011 AACR.\n

展開された著作権コードは次のようになります。

Cancer Res; 71(3); 1-11. \xC2\xA92011 AACR.\n

Rubyは、文字列がASCII-8BITとしてエンコードされており、my Rails appにこれを取得すると、これを取得します:

incompatible character encodings: ASCII-8BIT and UTF-8

この正規表現を使用して著作権コードを取り除くことができます

str.gsub(/[\x00-\x7F]/n,'?')

これを生産する

Cancer Res; 71(3); 1-11. ??2011 AACR.\n

しかし、どうすれば著作権記号(およびギリシャ文字などのさまざまな記号)変換済みをUTF-8の同じ記号に取得できますか?確かにそれは可能です...

Force_encodingの使用への参照がありますが、これは機能しません。

str.force_encoding('utf-8').encode

同様の問題を抱えている他の多くの人々がいることは知っていますが、うまくいく解決策をまだ見ていません。

44
craic.com

これは私のために働く:

#encoding: ASCII-8BIT
str = "\xC2\xA92011 AACR"
p str, str.encoding
#=> "\xC2\xA92011 AACR"
#=> #<Encoding:ASCII-8BIT>

str.force_encoding('UTF-8')
p str, str.encoding
#=> "©2011 AACR"
#=> #<Encoding:UTF-8>
67
Phrogz

次の2つの可能性があります。

  1. 入力データはすでにUTF-8ですが、Rubyは単にそれを知りません。「\ xC2\xA9」は著作権記号に有効なUTF-8であるため、これはあなたの場合のようです。その場合、Rubyに、force_encodingを使用してデータが既にUTF-8であることを伝える必要があります。

    たとえば、「\ xC2\xA9」.force_encoding( 'ASCII-8BIT')は、入力データの関連ビットを再作成します。そして、「\ xC2\xA9」.force_encoding( 'ASCII-8BIT')。force_encoding( 'UTF-8')は、Rubyが実際にUTF-8であり、望ましい結果。

  2. 入力データは他の何らかのエンコーディングであり、UTF-8にトランスコードするにはRubyが必要です。その場合、Ruby現在のエンコーディングは(ASCII-8BITはバイナリのRuby-speakです、実際のエンコーディングではありません)、それからRubyにトランスコードするように伝えます。

    たとえば、入力データがISO-8859-1だったとします。そのエンコードでは、著作権記号は「\ xA9」です。これにより、次のようなデータが生成されます: "\ xA9" .force_encoding( 'ISO-8859-1')そして、これは、Rubyを取得してUTF-8にトランスコードできることを示します。 "\ xA9" .force_encoding( 'ISO-8859-1')。encode( 'UTF-8')

27
Jason Heiss

私は、open-uri、iconv、Hpricotを使用して、ギリシャ語のWindowsエンコードページをスクレイプするスクリプトでこれを実行していました。

doc = open(DATA_URL)
doc.rewind
data = Hpricot(Iconv.conv('utf-8', "WINDOWS-1253", doc.readlines.join("\n")))

私はそれがRuby 1.8.7で、物事がどのようにRuby 1.9

6
Achilles

私は文字エンコーディングに問題があり、他の回答は役に立ちましたが、すべてのケースで機能しませんでした。これが、可能な場合はエンコードを強制し、不可能な場合は「?」を使用してトランスコードする、私が思いついた解決策です。解決策は次のとおりです。

  def encode str
    encoded = str.force_encoding('UTF-8')
    unless encoded.valid_encoding?
      encoded = str.encode("utf-8", invalid: :replace, undef: :replace, replace: '?')
    end
    encoded
  end

force_encodingはほとんどの場合機能しますが、それが失敗する文字列に遭遇しました。このような文字列では、無効な文字が置き換えられます。

 str = "don't panic: \xD3"
 str.valid_encoding?
 false
 str = str.encode("utf-8", invalid: :replace, undef: :replace, replace: '?')
 "don't panic: ?"
 str.valid_encoding?
 true

更新:上記のコードの実稼働環境で問題が発生しました。既知の問題テキストを使用して単体テストをセットアップし、このコードが必要なように機能することを確認することをお勧めします。バージョン2を思いついたら、この回答を更新します。

1
Jared Menard