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​​ 如何解释它们)。

在第二种情况下,您只想将任何讨厌的东西转储到您的 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 只是编码相同底层字符集的两种不同方式。

于 2012-07-07T16:37:41.927 回答
2

也许您正在 IRB 中运行此代码。我在使用 IRB 时遇到了很多编码问题。在这种情况下,请尝试将此代码保存为.rb文件并从命令行运行代码。

于 2012-07-07T13:43:45.100 回答