11

要将字符串转换为 UTF-8 并替换所有编码错误,您可以执行以下操作:

str.encode('utf-8', :invalid=>:replace)

唯一的问题是,如果已经是 UTF-8,它就不起作用str,在这种情况下,任何错误仍然存​​在:

irb> x = "foo\x92bar".encode('utf-8', :invalid=>:replace)
=> "foo\x92bar"
irb> x.valid_encoding?
=> false

引用Ruby 文档

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

显而易见的解决方法是先转换为不同的 Unicode 编码,然后再转换回 UTF-8:

str.encode('utf-16', :invalid=>:replace).encode('utf-8')

例如:

irb> x = "foo\x92bar".encode('utf-16', :invalid=>:replace).encode('utf-8')
=> "foo�bar"
irb> x.valid_encoding?
=> true

有没有更好的方法可以在不转换为虚拟编码的情况下做到这一点?

4

2 回答 2

19

Ruby 2.1 添加了一个String#scrub方法,可以满足您的需求:

2.1.0dev :001 > x = "foo\x92bar"
 => "foo\x92bar" 
2.1.0dev :002 > x.valid_encoding?
 => false 
2.1.0dev :003 > y = x.scrub
 => "foo�bar" 
2.1.0dev :004 > y.valid_encoding?
 => true 

相同的提交还会更改 的行为,encode以便在源和目标编码相同时起作用:

2.1.0dev :005 > x = "foo\x92bar".encode('utf-8', :invalid=>:replace)
 => "foo�bar" 
2.1.0dev :006 > x.valid_encoding?
 => true 

据我所知,在 2.1 之前没有内置的方法来执行此操作(否则scrub不需要),因此在 2.1 发布之前您需要使用一些解决方法并且您可以升级。

于 2013-10-03T18:21:44.723 回答
5

试试这个:

 "foo\x92bar".chars.select(&:valid_encoding?).join
  # => "foobar"

或者更换

"foo\x92bar".chars.map{|c| c.valid_encoding? ? c : "?"}.join
 # =>  "foo?bar"
于 2013-10-03T17:45:19.557 回答