7

在 IRB 中,我正在尝试以下操作:

1.9.3p194 :001 > foo = "\xBF".encode("utf-8", :invalid => :replace, :undef => :replace)
 => "\xBF" 
1.9.3p194 :002 > foo.match /foo/
ArgumentError: invalid byte sequence in UTF-8
from (irb):2:in `match'

任何想法出了什么问题?

4

3 回答 3

22

我猜它"\xBF"已经认为它是用 UTF-8 编码的,所以当你调用 时encode,它认为你正在尝试用 UTF-8 编码一个 UTF-8 字符串并且什么都不做:

>> s = "\xBF"
=> "\xBF"
>> s.encoding
=> #<Encoding:UTF-8>

\xBF不是有效的 UTF-8,所以这当然是胡说八道。但是,如果您使用 的三个参数形式encode

编码(dst_encoding,src_encoding [,选项])→ str

[...] 第二种形式返回str转码 from src_encodingto的副本dst_encoding

encode您可以通过告诉忽略字符串认为其编码是什么并将其视为二进制数据来强制解决此问题:

>> foo = s.encode('utf-8', 'binary', :invalid => :replace, :undef => :replace)
=> "�"

从上面认为它是 UTF-8 的s在哪里。"\xBF"

您也可以使用force_encodingons强制它为二进制,然后使用两个参数encode

>> s.encoding
=> #<Encoding:UTF-8>
>> s.force_encoding('binary')
=> "\xBF"
>> s.encoding
=> #<Encoding:ASCII-8BIT>
>> foo = s.encode('utf-8', :invalid => :replace, :undef => :replace)
=> "�"
于 2012-05-05T21:50:59.967 回答
5

如果您只使用 ascii 字符,则可以使用

>> "Hello \xBF World!".encode('utf-8', 'binary', :invalid => :replace, :undef => :replace)
=> "Hello � World!"

但是如果我们对在 ascii 中无效的有效 UTF8 字符使用相同的方法会发生什么

>> "¡Hace \xBF mucho frío!".encode('utf-8', 'binary', :invalid => :replace, :undef => :replace)
=> "��Hace � mucho fr��o!"

哦哦!我们希望 frío 保持口音。这是一个保留有效 UTF8 字符的选项

>> "¡Hace \xBF mucho frío!".chars.select{|i| i.valid_encoding?}.join
=> "¡Hace  mucho frío!"

同样在 Ruby 2.1 中有一个新方法scrub可以解决这个问题

>> "¡Hace \xBF mucho frío!".scrub
=> "¡Hace � mucho frío!"
>> "¡Hace \xBF mucho frío!".scrub('')
=> "¡Hace  mucho frío!"
于 2014-11-30T03:19:20.623 回答
2

如果您使用显式代码页阅读源文本文件,则此问题已修复:

File.open( 'thefile.txt', 'r:iso8859-1' )
于 2013-03-19T18:41:41.047 回答