web-dev-qa-db-ja.com

Ruby文字列エンコーディングをISO-8859-1からUTF-8に変換しても機能しない

文字列をISO-8859-1エンコーディングからUTF-8に変換しようとしていますが、機能しないようです。これは私がirbで行ったことの例です。

_irb(main):050:0> string = 'Norrlandsvägen'
=> "Norrlandsvägen"
irb(main):051:0> string.force_encoding('iso-8859-1')
=> "Norrlandsv\xC3\xA4gen"
irb(main):052:0> string = string.encode('utf-8')
=> "Norrlandsvägen" 
_

Iso-8859-1のNorrlandsvägenがutf-8のNorrlandsvägenに変換される理由がわかりません。

エンコード、エンコード!、エンコード(destinationEncoding、originalEncoding)、iconv、force_encoding、および考えられるあらゆる種類の奇妙な回避策を試しましたが、何も機能しないようです。誰かが私を助けて/私を正しい方向に向けることができますか?

ルビー初心者はまだ狂ったように髪を引っ張っていますが、ここでのすべての返信に感謝しています...:)

この質問の背景:いくつかのWebサイト(iso-8859-1エンコーディング)からxmlファイルをダウンロードしてストレージに保存するgemを作成していますが、最初にutf-8に変換したいと思います。しかし、Norrlandsvägenのような言葉は私を台無しにし続けます。本当にどんな助けでも大歓迎です!

[更新]:irbコンソールでこのようなテストを実行すると、異なる動作が発生する可能性があることに気づきました。実際のコードには次のようなものがあります。

_def convert_encoding(string, originalEncoding) 
  puts "#{string.encoding}" # ASCII-8BIT
  string.encode(originalEncoding)
  puts "#{string.encoding}" # still ASCII-8BIT
  string.encode!('utf-8')
end
_

しかし、最後の行は私に次のエラーを与えます:

_Encoding::UndefinedConversionError - "\xC3" from ASCII-8BIT to UTF-8
_

以下の@Amadanの回答のおかげで、実行すると_\xC3_が実際にirbに表示されることに気付きました。

_irb(main):001:0> string = 'ä'
=> "ä"
irb(main):002:0> string.force_encoding('iso-8859-1')
=> "\xC3\xA4"
_

また、string.encode(originalEncoding)の結果に新しい変数を割り当てようとしましたが、さらに奇妙なエラーが発生しました。

_newString = string.encode(originalEncoding)
puts "#{newString.encoding}" # can't even get to this line...
newString.encode!('utf-8')
_

エラーは_Encoding::UndefinedConversionError - "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to ISO-8859-1_です

私はまだこのエンコーディングの混乱のすべてでかなり迷っていますが、私はすべての返信に本当に感謝しており、みんなが私にくれたのを助けます!トンありがとう! :)

10
charint

UTF-8で文字列を割り当てます。 äが含まれています。 UTF-8は、äを2バイトで表します。

string = 'ä'
string.encoding
# => #<Encoding:UTF-8>
string.length
# 1
string.bytes
# [195, 164]

次に、基になる表現を実際に変更せずに、バイトをISO-8859-1であるかのように強制的に解釈します。これにはäは含まれていません。 äの2文字が含まれています。

string.force_encoding('iso-8859-1')
# => "\xC3\xA4"
string.length
# 2
string.bytes
# [195, 164]

次に、それをUTF-8に変換します。これは再解釈ではなく翻訳であるため、2文字を保持しますが、UTF-8でエンコードされます。

string = string.encode('utf-8')
# => "ä" 
string.length
# 2
string.bytes
# [195, 131, 194, 164]

あなたが見逃しているのは、あなたが元々あなたのWebサービスからのようにISO-8859-1文字列を持っていないという事実です-あなたは意味不明です。幸い、これはすべてコンソールテストに含まれています。適切な入力エンコーディングを使用してWebサイトの応答を読み取れば、すべて正常に機能するはずです。

コンソールテストでは、適切なISO-8859-1文字列から始めれば、すべてが機能することを示しましょう。

string = 'Norrlandsvägen'.encode('iso-8859-1')
# => "Norrlandsv\xE4gen"
string = string.encode('utf-8')
# => "Norrlandsvägen"

[〜#〜] edit [〜#〜]特定の問題の場合、これは機能するはずです。

require 'net/https'
uri = URI.parse("https://rusta.easycruit.com/intranet/careerbuilder_se/export/xml/full")
options = {
  :use_ssl => uri.scheme == 'https', 
  :verify_mode => OpenSSL::SSL::VERIFY_NONE
}
response = Net::HTTP.start(uri.Host, uri.port, options) do |https|
  https.request(Net::HTTP::Get.new(uri.path))
end
body = response.body.force_encoding('ISO-8859-1').encode('UTF-8')
15
Amadan

force_encodingencode には違いがあります。前者は文字列のエンコーディングを設定しますが、後者は実際には文字列の内容を新しいエンコーディングにトランスコードします。したがって、次のコードが問題の原因になります。

string = "Norrlandsvägen"
string.force_encoding('iso-8859-1')
puts string.encode('utf-8') # Norrlandsvägen

次のコードは実際にはコンテンツを正しくエンコードします。

string = "Norrlandsvägen".encode('iso-8859-1')
string.encode!('utf-8')

irbで実行されている例を次に示します。

irb(main):023:0> string = "Norrlandsvägen".encode('iso-8859-1')
=> "Norrlandsv\xE4gen"
irb(main):024:0> string.encoding
=> #<Encoding:ISO-8859-1>
irb(main):025:0> string.encode!('utf-8')
=> "Norrlandsvägen"
irb(main):026:0> string.encoding
=> #<Encoding:UTF-8>
1
Aeyrix

上記の答えは的確でした。具体的にはここでこの点:

Force_encodingとencodeには違いがあります。前者は文字列のエンコーディングを設定しますが、後者は実際には文字列の内容を新しいエンコーディングにトランスコードします。

私の状況では、iso-8859-1エンコーディングのテキストファイルがありました。デフォルトでは、RubyはUTF-8エンコーディングを使用するため、エンコーディングを指定せずにファイルを読み取ろうとすると、エラーが発生します。

_results = File.read(file)
results.encoding
 => #<Encoding:UTF-8> 
 results.split("\r\n")
ArgumentError: invalid byte sequence in UTF-8
_

異なるエンコーディングの文字が異なるバイト長で表されるため、無効なバイトシーケンスエラーが発生します。したがって、FileAPIにエンコーディングを指定する必要があります。 force_encodingのように考えてください。

_results = File.read(file, encoding: "iso-8859-1")
_

だからすべてが良いですよね?いいえ、UTF-8文字エンコードを使用してiso-8859-1文字列の解析を開始する場合は除きます。

_results = File.read(file, encoding: "iso-8859-1")
results.each do |line|
  puts line.split('¬')
end
Encoding::CompatibilityError: incompatible character encodings: ISO-8859-1 and UTF-8
_

なぜこのエラー? '¬'はUTF-8として表されるためです。 ISO-8859-1文字列に対してUTF-8文字シーケンスを使用しています。それらは互換性のないエンコーディングです。したがって、ファイルをISO-8859-1として読み取った後、RubyにそのISO-8859-1をUTF-8にエンコードするように要求できます。これで、次の操作を行うことができます。 UTF-8文字列であるため、問題はありません。

_results = File.read(file, encoding: "iso-8859-1").encode('UTF-8')
results.encoding
results = results.split("\r\n")
results.each do |line|
  puts line.split('¬')
end
_

最終的に、一部のRuby APIでは、force_encoding('ISO-8859-1')を使用する必要はありません。代わりに、APIに期待されるエンコーディングを指定するだけです。ただし、に変換し直す必要があります。 UTF-8文字列で解析する場合はUTF-8。

1
Donato