web-dev-qa-db-ja.com

csvデータをインポートするとき、「UTF-8の無効なバイトシーケンス」をどのように排除するか

ユーザーがcsv経由でデータをインポートできるようにします(Ruby 1.9.2を使用しているため、csvが高速です)。

もちろん、ユーザーデータであるため、適切にサニタイズされない可能性があります。

/ indexメソッドでデータを表示しようとすると、widget.nameフィールドのいずれかを表示するerbを指すエラー「UTF-8の無効なバイトシーケンス」が表示されることがあります。

インポートを実行するとき、受信データを有効にするために強制したい... Ruby演算子は、文字列を有効なutf8文字列にマッピングします。

goodstring = badstring.no_more_invalid_bytes

「不良」データの1つの例は、ハイフンのように見えますが、通常のアスキーハイフンではないcharです。 utf-8以外の文字を、相当するASCII文字に変換することをお勧めします(umlat-uは例としてuに進みます)が、単に文字を削除するだけで大​​丈夫です。

これは大量のデータをインポートするときなので、できれば高速の組み込み演算子である必要があります...


注:これはデータの例です。ファイルはWindowsから来て、8ビットASCIIです。それをインポートし、erbで(widget.nameではなく)widget.name.inspectを表示すると、「Chains\x96 Accessories」が得られます。

したがって、データの一例は、実際には8ビットコード96である「ハイフン」です。

--- csv parseを変更してfldval = d.encode( 'UTF-8')を割り当てると、このエラーがスローされます。

Encoding::UndefinedConversionError in StoresController#importfinderitems
"\x96" from ASCII-8BIT to UTF-8

私たちが探しているのは、単に非ASCIIを削除したとしても、Originのタイプに関係なく有効なutf8になるように強制する簡単な方法です。


エンコードを強制するほど「ナイス」ではありませんが、これはインポート時間をわずかに犠牲にして機能します:d.to_s.strip.gsub(/\P {ASCII} /、 '')ありがとう、Mladen!

59
jpwynn

Ruby 1.9 CSVには、m17nで動作する新しいパーサーがあります。パーサーは、文字列内のIOオブジェクトのエンコーディング。次のメソッド:::foreach, ::open, ::read, and ::readlinesはオプションのオプションを取ります:encodingエンコードを指定できます。

例えば:

CSV.read('/path/to/file', :encoding => 'windows-1251:utf-8')

すべての文字列をUTF-8に変換します。

また、より標準的なエンコーディング名「ISO-8859-1」を使用できます

CSV.read('/..', {:headers => true, :col_sep => ';', :encoding => 'ISO-8859-1'})
121
Trung Lê

私は、UTF-8以外のエンコーディングを使用した1.9.2の外部ファイルの読み取りに関する同様の質問に答えました。私はその答えがあなたに大いに役立つと思います: Character Encoding issue in Rails v3/Ruby 1.9.2

確実に変換するには、ソースエンコーディングを知る必要があることに注意してください。これを判断するのに役立つ他の回答でリンクしたライブラリのようなライブラリがあります。

また、ファイルからデータをロードしていない場合は、1.9.2で文字列のエンコードを非常に簡単に変換できます。

'string'.encode('UTF-8')

ただし、別のエンコーディングで文字列を作成することはまれであり、可能であれば、環境に読み込まれるときに変換するのが最善です。

13
coreyward
CSV.parse(File.read('/path/to/csv').scrub)
10
Bill Lipa

Ruby 1.9は、無効な検出と置換により文字列エンコーディングを変更できます。

str = str.encode('UTF-8', :invalid => :replace)

エンコードが不明なファイルからロードされた文字列などの異常な文字列の場合、正規表現、#gsub、または#deleteの代わりに#encodeを使用するのが賢明です。これらはすべて文字列を解析する必要があるためです解析できないため、これらのメソッドは失敗します。

次のようなメッセージが表示された場合:

error ** from ASCII-8BIT to UTF-8

次に、おそらくUTF-8にあるバイナリ文字列を変換しようとしているので、UTF-8を強制できます。

str.force_encoding('UTF-8')

元の文字列がバイナリUTF-8ではないことがわかっている場合、または出力文字列に不正な文字が含まれている場合は、Rubyエンコーディング音訳を参照してください。

7

Railsを使用している場合、次の方法で修正を試みることができます。

'Your string with strange stuff #@~'.mb_chars.tidy_bytes

無効なutf-8文字を削除し、有効な文字に置き換えます。詳細: https://apidock.com/Rails/String/mb_chars

4
dom

CSVファイルをGoogle Docs Spreadsheetにアップロードし、CSVファイルとして再ダウンロードします。インポートして出来上がり! (私の場合は働いた)

おそらく、Googleはそれを必要な形式に変換します。

ソース: TF-8エンコードでExcelからCSVへ

1
Jonathan Lin

こうするだけ

anyobject.to_csv(:encoding => 'utf-8')

他の誰かが述べたように、スクラブはRuby 2.1+でこれをクリーンアップするのにうまく機能します。大きなファイルがある場合は、すべてをメモリに読み込む必要がないため、スクラブを使用できますこのような:

data = IO::read(file_path).scrub("")
CSV.parse(data, :col_sep => ',', :headers => true)  do |row|
   puts row
end
0
Andy Fraley