在 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'
任何想法出了什么问题?
我猜它"\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
转码 fromsrc_encoding
to的副本dst_encoding
。
encode
您可以通过告诉忽略字符串认为其编码是什么并将其视为二进制数据来强制解决此问题:
>> foo = s.encode('utf-8', 'binary', :invalid => :replace, :undef => :replace)
=> "�"
从上面认为它是 UTF-8 的s
在哪里。"\xBF"
您也可以使用force_encoding
ons
强制它为二进制,然后使用两个参数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)
=> "�"
如果您只使用 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!"
如果您使用显式代码页阅读源文本文件,则此问题已修复:
File.open( 'thefile.txt', 'r:iso8859-1' )