私はRuby 1.9.2を使用しています
私はCSVファイルを解析にフランス語の単語(例:spécifié)を含め、その内容をMySQLデータベースに配置しようとしています。
CSVファイルから行を読み取ると、
_file_contents = CSV.read("csvfile.csv", col_sep: "$")
_
要素はASCII-8BITエンコードされた文字列として返され(spécifiéはsp\xE9cifi\xE9になります)、「spécifié」などの文字列はMySQLデータベースに適切に保存されません。
Yehuda Katz は、ASCII-8BITは実際には「バイナリ」データであり、CSVには適切なエンコーディングの読み方がわからないことを意味します。
そのため、CSVで次のようなエンコードを強制しようとした場合:
file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "UTF-8")
次のエラーが表示されます
_ArgumentError: invalid byte sequence in UTF-8:
_
元のASCII-8BITエンコード文字列に戻って、CSVがASCII-8BITとして読み込んだ文字列を調べると、「Nonspécifié」ではなく「Non sp\xE9cifi\xE9」のように見えます。
この"Non sp\xE9cifi\xE9".encode("UTF-8")
を実行しても、「Non sp\xE9cifi\xE9」を「Nonspécifié」に変換できません。
私はこのエラーを取得するため:
_Encoding::UndefinedConversionError: "\xE9" from ASCII-8BIT to UTF-8
_、
aSCII-8BITは実際には適切な文字列「エンコード」ではないため、Katzが示したようになります。
質問:
deceze は正しい、つまりISO8859-1(別名Latin-1)でエンコードされたテキストです。これを試して:
file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1")
それがうまくいかない場合は、 Iconv
を使用して、次のような個々の文字列を修正できます。
require 'iconv'
utf8_string = Iconv.iconv('utf-8', 'iso8859-1', latin1_string).first
latin1_string
は"Non sp\xE9cifi\xE9"
、次にutf8_string
は"Non spécifié"
。また、Iconv.iconv
は一度に配列全体を解体できます。
utf8_strings = Iconv.iconv('utf-8', 'iso8859-1', *latin1_strings)
新しいルビーを使用すると、次のようなことができます。
utf8_string = latin1_string.force_encoding('iso-8859-1').encode('utf-8')
ここで、latin1_string
はASCII-8BITであると考えていますが、実際にはISO-8859-1にあります。
Ruby> = 1.9を使用できます
file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1:utf-8")
ISO8859-1:utf-8
の意味:csvファイルはISO8859-1-エンコードされていますが、コンテンツをutf-8に変換します
より詳細なコードが必要な場合は、次を使用できます。
file_contents = CSV.read("csvfile.csv", col_sep: "$",
external_encoding: "ISO8859-1",
internal_encoding: "utf-8"
)
私はしばらくの間この問題に対処してきましたが、他のどのソリューションも私のために機能しませんでした。
トリックを作ったのは、競合するstringをbinaryファイルに保存してから、通常どおりファイルを読み取り、このstringを使用してCSVモジュール:
tempfile = Tempfile.new("conflictive_string")
tempfile.binmode
tempfile.write(conflictive_string)
tempfile.close
cleaned_string = File.read(tempfile.path)
File.delete(tempfile.path)
csv = CSV.new(cleaned_string)