为什么我在ruby 2.0中得到“ArgumentError - US-ASCII中的无效字节序列”

时间:2014-10-22 00:04:37

标签: ruby character-encoding

我有一些代码可以处理来自(不是rails应用程序)的Web请求,并且使用以下几行,

str.encode!(::Encoding::ASCII, :undef => :replace, :invalid => :replace, :replace => '')
str.gsub(/[\\\%\']/, '')

str.gsub调用获得异常"ArgumentError - invalid byte sequence in US-ASCII"

我的印象是,如果我用encode!调用::Encoding::ASCII方法,它会处理这个,但显然不是;我正在尝试处理的字符在我的文本日志文件中显示为%91。任何人都知道为什么encode!电话没有达到我预期的效果?

我不知道字符串之前是什么样的 - 这只发生在生产环境中,而我正在从日志文件进行调试,其中的值可能是以原始方式以外的某种方式编码的。我将尝试使用Marshal.dump'ing对象来保存它并在下次发生时在本地重现它。

1 个答案:

答案 0 :(得分:1)

In Ruby 2.0 (and earlier), trying to use encode (or encode!) on a string that is already in the target encoding is a no-op

  

请注意,从编码enc到相同编码enc的转换是无操作的,即返回的接收器没有任何更改,并且即使存在无效也不会引发异常字节。

在您的情况下,如果str已经具有ASCII编码,则encode调用将不会执行任何操作,因此任何无效字节将保留并导致后续gsub调用中的错误。

Ruby 2.1不会发生这种情况,它还引入了scrub method作为删除无效字节的简单方法。

如果您无法升级您的Ruby版本,您可以通过更改为不同的编码并返回来解决此问题,例如:

str.encode(::Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '').encode(::Encoding::ASCII)

更好的解决方案是确保您正确处理进入应用程序的所有文本数据的字符编码,并在进入时根据需要进行转换(通常为UTF8)。如何执行此操作取决于数据的来源。

在您的示例中,看起来数据正在CP-1252 encoding中提交(字符U+2018 LEFT SINGLE QUOTATION MARK使用该编码中的字节0x91进行编码)。如果您确定数据始终采用此编码,则可以通过以下方式解决此问题:

str.force_encoding(Encoding::Windows_1252).encode(Encoding::UTF_8)