11

私はこのエラーについて複数の同様の質問があることを知っています、そして私は運がなくてそれらの多くを試しました。私が抱えている問題はバイトに関係していて、\xA1投げています

ArgumentError:UTF-8の無効なバイトシーケンス

私は次のことを試みましたが成功しませんでした:

"\xA1".encode('UTF-8', :undef => :replace, :invalid => :replace,
    :replace => "").sub('', '')
"\xA1".encode('UTF-8', :undef => :replace, :invalid => :replace,
    :replace => "").force_encoding('UTF-8').sub('', '')
"\xA1".encode('UTF-8', :undef => :replace, :invalid => :replace,
    :replace => "").encode('UTF-8').sub('', '')

各行は私のためにエラーをスローします。私は何が間違っているのですか?

アップデート:

上記の行はIRBでのみ失敗します。ただし、同じString#encodeメソッドと引数を使用してCVSファイルの行をエンコードするようにアプリケーションを変更したところ、ファイルから行を読み取るときに同じエラーが発生します(注:同じ文字列で操作を実行すると機能しますIOを使用しない)。

bad_line = "col1\tcol2\tbad\xa1"

bad_line.sub('', '') # does NOT fail
puts bad_line # => col1 col2    bad?

tmp = Tempfile.new 'foo' # write the line to a file to emulate real problem
tmp.puts bad_line
tmp.close

tmp2 = Tempfile.new 'bar'

begin
  IO.foreach tmp.path do |line|
    line.encode!('UTF-8', :undef => :replace, :invalid => :replace, :replace => "")
    line.sub('', '') # fail: invalid byte sequence in UTF-8
    tmp2.puts line
  end
  tmp2.close

  # this would fail if the above error didn't halt execution
  CSV.foreach(tmp2.path) do |row|
    puts row.inspect # fail: invalid byte sequence in UTF-8
  end
ensure
  tmp.unlink
  tmp2.close
  tmp2.unlink
end
4

2 に答える 2

32

ruby は文字列エンコーディングが既に utf8 であると認識しているように見えるので、

line.encode!('UTF-8', :undef => :replace, :invalid => :replace, :replace => "")

宛先のエンコーディングが現在のエンコーディングと同じであるため、実際には何もしません(少なくともそれは のコードの私の解釈ですtranscode.c

ここでの本当の問題は、開始データが utf-8 ではないエンコーディングで有効かどうか、またはこれが utf-8 であるはずのデータであるが破棄したいいくつかのいぼがあるかどうかです。

最初のケースでは、このエンコーディングが何であるかを ruby​​ に伝えるのが正しいことです。ファイルを開くときにこれを行うことができます

File.open('somefile', 'r:iso-8859-1')

ファイルを開き、その内容を iso-8859-1 として解釈します

Ruby でトランスコードすることもできます

File.open('somefile', 'r:iso-8859-1:utf-8')

ファイルを iso-8859-1 として開きますが、そこからデータを読み取ると、バイトは utf-8 に変換されます。

を呼び出しforce_encodingて、文字列のエンコーディングが何であるかを ruby​​ に伝えることもできます (これはバイトをまったく変更せず、ruby にバイトの解釈方法を伝えるだけです)。

2 番目のケースでは、厄介なものを utf-8 に入れたものをダンプしたいだけですが、これencode!はノーオペレーションであるため、そのまま呼び出すことはできません。Ruby 2.1 以降ではString#scrubを使用できますが、以前のバージョンではこれを行うことができます

line.encode!('UTF-16', :undef => :replace, :invalid => :replace, :replace => "")
line.encode!('UTF-8')

最初に utf-16 に変換します。これは別のエンコーディングであるため、実際には ruby​​ が無効なシーケンスを置き換えます。その後、utf-8 に戻すことができます。utf-8 と utf-16 は同じ基になる文字セットをエンコードする 2 つの異なる方法であるため、余分なデータが失われることはありません。

于 2012-07-07T16:37:41.927 に答える
2

このコードを IRB で実行している可能性があります。IRB で多くのエンコードの問題が発生しました。この場合、このコードを.rbファイルとして保存し、コマンド ラインからコードを実行してみてください。

于 2012-07-07T13:43:45.100 に答える